fauhdlc-20130704/0000775000175000017500000000000012165333100012774 5ustar potyrapotyrafauhdlc-20130704/misc/0000775000175000017500000000000012165333076013743 5ustar potyrapotyrafauhdlc-20130704/misc/filetype.vim0000664000175000017500000000010110757332310016264 0ustar potyrapotyra" fauhdlc intermedate code au BufNewFile,BufRead *.ic setf ic fauhdlc-20130704/misc/ic.vim0000664000175000017500000000230411457272572015060 0ustar potyrapotyra" Vim syntax file " Language: fauhdlc intermediate code " Maintainer: Stefan Potyra " Last Change: 2008 Feb 15 " Filenames: *.ic syn case ignore syn keyword Statement mov add sub je jmp getsig wakeat syn keyword Statement imul call wakeon log abort syn keyword Statement update jb jne jbe aoffset roffset syn keyword Statement data return suspend proc div gettime syn keyword Statement begintr endtr setparm connect getparm syn match Special "\.STACK" syn match Special "\.TRANSFER" syn match Special "\.TEXT" syn match Special "\.REGISTERS" syn match Special "\.TYPES" syn match Special "SIGNAL" syn match Special "VARIABLE" syn match Special "DRIVER" syn match Special "CONTAINER" syn match Special "END CONTAINER" syn match Special "RESOLVEDBY" syn match Type "TYPE [a-zA-Z0-9_]\+ is" syn match Type "[a-zA-Z0-9_]*->" syn match Type "[a-zA-Z0-9_]\+\[" syn match Type "[a-zA-Z0-9_]*\( \)*:=" syn match String "\"[a-zA-Z0-9:_]*\"" syn match Identifier "[a-z_][0-9a-z_]*:" syn match Number "$-\?[0-9]*[lf]" syn match Identifier "@[a-z0-9_]*" syn match Comment "{[^}]*}" syn case match let b:current_syntax = "ic" " vim: ts=8 fauhdlc-20130704/misc/install_ln.sh0000775000175000017500000000216611265110517016437 0ustar potyrapotyra#!/bin/sh # $Id: install_ln.sh 4813 2009-10-13 14:40:15Z potyra $ # # mimic install but use soft links instead # # Copyright (C) 2009 FAUmachine Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. if [ $1 = '-c' ]; then # -c -> ignored shift fi if [ $1 = '-m' ]; then # mode -> ignore shift shift fi eval TRG="\${$#}" # more than two arguments? -> target is directory. if [ $# -gt 2 ]; then if [ ! -d "$TRG" ]; then echo "$TRG is not a directory." exit 1 fi fi TARGET_IS_DIR=0 if [ -d "$TRG" ]; then TARGET_IS_DIR=1 fi while [ $# -gt 1 ]; do SRC=$1 shift if [ ! -e "$(pwd)/$SRC" ]; then echo "$SRC no such file or directory." exit 1 fi if [ $TARGET_IS_DIR -eq 1 ]; then DST="$TRG/$(basename $SRC)" else DST="$TRG" fi if [ -e "$DST" -a \( ! \( -h "$DST" \) \) ]; then echo "$DST exists and is not a symbolic link. Skipping." continue fi echo ln -sf "$(pwd)/$SRC" "$TRG" ln -sf "$(pwd)/$SRC" "$TRG" done fauhdlc-20130704/misc/Makefile.am0000664000175000017500000000040511133353257015773 0ustar potyrapotyra# $Id: Makefile.am 4271 2009-01-14 12:12:31Z potyra $ # # Copyright (C) 2009 FAUmachine Team . # This program is free software, GPL-2 (or any later version). See COPYING. EXTRA_DIST = \ filetype.vim \ ic.vim \ install_ln.sh \ README fauhdlc-20130704/misc/README0000664000175000017500000000034610757332310014621 0ustar potyrapotyraEnable syntax highlighting for intermediate code in vim: ic.vim: syntax highlight defintions filetype.vim: automatically specify file type for *.ic To enable, copy ic.vim -> ~/.vim/after/syntax/ filetype.vim -> ~/.vim/after/ fauhdlc-20130704/AUTHORS0000664000175000017500000000430011137610415014046 0ustar potyrapotyraVolkmar Sieh Had the Idea... Main Author FAUmachine core Kerstin Buchacker Fault Injection Public relations Hans-Joerg Hoexer FAUmachine core Raoul van Putten GUI Co-Tung Truong X support and graphics Oliver Tschäche expect experimentation sandbox serial components test scenarios Matthias Sand FAUmachine core Thomas Glanzmann IDE NE2000 Floppy Simulator Roland Karch Test Matthias Bickel Documentation Ivan Dedinski Serial Simulator Windows Port Marcel Ritter BIOS Peter Asemann Bridge for Binding Real Hardware into the Virtual Machine Parallel Port Simulator Josef Angermeier Virtual Sound 1MB-BIOS Stefan Potyra VHDL simulation Modem Simulator Martin Waitz Documentation Network bridge Build system Christoph Kloeters Speedup the emulation by patching host-kernels Michael Meier E100 NIC x86-64 (AMD64) Support (host & guest) Tobias Werth Gtk GUI Florian Eckert Timesyncronisation Christoph Dörfler Design of automatic tests Tobias Jordan Serial terminal ACPI Stefan Leuchsenring Floppy Simulator Stephan Sigwart Improved patternmatcher Horst Schirmeier USB Gernot Payer Acceleration kernel modules Matthias Körber PCMCIA CardBus controller Helmar Wieland Cirrus accelerated SVGA card Alexander Benker activity designer fauhdlc-20130704/interpreter/0000775000175000017500000000000012165333077015354 5ustar potyrapotyrafauhdlc-20130704/interpreter/fauhdli.c0000664000175000017500000003054711457077634017154 0ustar potyrapotyra/* $Id: fauhdli.c 4974 2010-10-18 17:10:52Z potyra $ * Interpreter library. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "fauhdli_private.h" #include #include #include #include #include "lookup_symbols.h" #include "kernel.h" #include "glue-log.h" #include "glue-main.h" #include "signals.h" #include "trace.h" #define ARRAY_SIZE(t) (sizeof t / sizeof(t[0])) /* definition of scanner */ extern FILE *yyin; /* definition of parser */ extern int yyparse(struct fauhdli *instance, const char *filename); static void fauhdli_destroy_operand( struct operand *op, const struct glue_vhdl_cb *callbacks ) { if (op == NULL) { return; } switch (op->kind) { case OPERAND_TARGET: callbacks->free(op->bytype.target.name); break; case OPERAND_REFERENCE: callbacks->free(op->bytype.data.name); break; case OPERAND_IMMEDIATE: case OPERAND_INDIRECT: case OPERAND_REGISTER: /* nothing to do */ break; } callbacks->free(op); } static void fauhdli_destroy_annotations( struct slist *annotations, const struct glue_vhdl_cb *callbacks ) { struct slist_entry *i; if (annotations == NULL) { return; } for (i = annotations->first; i != NULL; i = i->next) { struct annotation_spec *a = (struct annotation_spec*)i->data; if (a->string_value != NULL) { callbacks->free(a->string_value); } callbacks->free(a->name); callbacks->free(a); } slist_destroy(annotations, callbacks->free); } static void fauhdli_destroy_type_element( struct type_element *elem, const struct glue_vhdl_cb *callbacks ) { if (elem == NULL) { return; } callbacks->free(elem->name); if (elem->initial_list != NULL) { struct slist_entry *i; for (i = elem->initial_list->first; i != NULL; i = i->next) { fauhdli_destroy_operand( (struct operand *)i->data, callbacks); } slist_destroy(elem->initial_list, callbacks->free); } fauhdli_destroy_annotations(elem->annotations, callbacks); callbacks->free(elem); } /** destroy one data definition. * @param d data definition to destroy. */ static void fauhdli_destroy_data_definition( struct data_definition *d, const struct glue_vhdl_cb *callbacks ) { if (d == NULL) { return; } callbacks->free(d->name); fauhdli_destroy_type_element(d->type, callbacks); fauhdli_destroy_annotations(d->annotations, callbacks); callbacks->free(d); } /** destroy one type declaration. * @param t type declaration to destroy. */ static void fauhdli_destroy_type_declaration( struct type_declaration *t, const struct glue_vhdl_cb *callbacks ) { struct slist_entry *i; if (t == NULL) { return; } assert(t->elements != NULL); for (i = t->elements->first; i != NULL; i = i->next) { fauhdli_destroy_type_element( (struct type_element*)i->data, callbacks); } slist_destroy(t->elements, callbacks->free); callbacks->free(t); } /** destroy a type list. * @param seg type list to destroy. * FIXME: cleanup wrt. fauhdli_destroy_data_seg. */ static void fauhdli_destroy_type_seg( struct slist *seg, const struct glue_vhdl_cb *callbacks ) { struct slist_entry *i; if (seg == NULL) { return; } for (i = seg->first; i != NULL; i = i->next) { fauhdli_destroy_type_declaration( (struct type_declaration *)i->data, callbacks); } slist_destroy(seg, callbacks->free); } /** destroy a transfer or stack segment. * @param seg transfer or stack segment to destroy. */ static void fauhdli_destroy_data_seg( struct slist *seg, const struct glue_vhdl_cb *callbacks ) { struct slist_entry *i; if (seg == NULL) { return; } for (i = seg->first; i != NULL; i = i->next) { fauhdli_destroy_data_definition( (struct data_definition*)i->data, callbacks); } slist_destroy(seg, callbacks->free); } static void fauhdli_destroy_opcode( struct opcode *opcode, const struct glue_vhdl_cb *callbacks ) { if (opcode == NULL) { return; } fauhdli_destroy_operand(opcode->op1, callbacks); fauhdli_destroy_operand(opcode->op2, callbacks); fauhdli_destroy_operand(opcode->op3, callbacks); fauhdli_destroy_type_element(opcode->indexed_type, callbacks); fauhdli_destroy_annotations(opcode->annotations, callbacks); switch (opcode->kind) { case OPCODE_LABEL: callbacks->free(opcode->label); break; default: break; } callbacks->free(opcode); } /** destroy a text segment. * @param seg text segment to destroy. */ static void fauhdli_destroy_text_seg( struct slist *seg, const struct glue_vhdl_cb *callbacks ) { struct slist_entry *i; if (seg == NULL) { return; } for (i = seg->first; i != NULL; i = i->next) { fauhdli_destroy_opcode((struct opcode *)i->data, callbacks); } slist_destroy(seg, callbacks->free); } /** destroy the code_container hierarchy again recursively. * @param instance fauhdli instance. */ static void fauhdli_destroy_container( struct code_container *container, const struct glue_vhdl_cb *callbacks ) { struct slist_entry *i; assert(container != NULL); callbacks->free(container->name); fauhdli_destroy_type_seg(container->type_definitions, callbacks); fauhdli_destroy_data_seg(container->transfer_segment, callbacks); fauhdli_destroy_data_seg(container->stack_segment, callbacks); fauhdli_destroy_text_seg(container->text_segment, callbacks); if (container->sub_containers != NULL) { for (i = container->sub_containers->first; i != NULL; i = i->next) { fauhdli_destroy_container( (struct code_container *)i->data, callbacks); } slist_destroy(container->sub_containers, callbacks->free); } callbacks->free(container); } static void fauhdli_destroy_signals( struct slset *sigs, const struct glue_vhdl_cb *callbacks ) { struct slset_entry *i; for (i = sigs->first; i != NULL; i = i->next) { signal_destroy((struct signal *)i->data, callbacks); } slset_destroy(sigs, callbacks->free); } static bool fauhdli_parse(struct fauhdli *instance, const char *file_name) { int ret; assert(file_name != NULL); yyin = fopen(file_name, "r"); if (yyin == NULL) { instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", __func__, "Failed to open file \"%s\": %s\n", file_name, strerror(errno)); return false; } ret = yyparse(instance, file_name); if (ret != 0) { instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", __func__, "Failed to parse file \"%s\"\n", file_name); ret = fclose(yyin); assert(ret >= 0); return false; } ret = fclose(yyin); assert(ret >= 0); return true; } static void fauhdli_setup_callbacks( struct fauhdli *instance, const struct glue_vhdl_cb *callbacks ) { if (callbacks == NULL) { memset(&instance->callbacks, 0, sizeof(instance->callbacks)); } else { memcpy(&instance->callbacks, callbacks, sizeof(instance->callbacks)); } if ( instance->callbacks.malloc == NULL || instance->callbacks.free == NULL) { instance->callbacks.malloc = malloc; instance->callbacks.free = free; } if (instance->callbacks.log == NULL) { instance->callbacks.log = (void (*)(int, const char *, const char *, const char *, ...))fauhdli_log; } if (instance->callbacks.time_virt == NULL || instance->callbacks.time_call_at == NULL || instance->callbacks.time_call_delete == NULL || instance->callbacks.quit == NULL) { /* any scheduling callback set, but not all? -> error */ if (instance->callbacks.time_virt != NULL || instance->callbacks.time_call_at != NULL || instance->callbacks.time_call_delete != NULL || instance->callbacks.quit != NULL) { instance->callbacks.log(FAUHDLI_LOG_ERROR, "fauhdli", "setup", "Some, but not all callbacks for " "scheduling set. Overriding.\n"); } instance->callbacks.time_virt = fauhdli_time_virt; instance->callbacks.time_call_at = fauhdli_time_call_at; instance->callbacks.time_call_delete = fauhdli_time_call_delete; instance->callbacks.quit = fauhdli_simulation_quit; } } struct opcode * fauhdli_alloc_opcode( enum opcode_kind kind, const struct glue_vhdl_cb *callbacks ) { /* FIXME calllbacks */ struct opcode *ret = callbacks->malloc(sizeof(struct opcode)); assert(ret != NULL); ret->kind = kind; ret->label = NULL; ret->op1 = NULL; ret->op2 = NULL; ret->op3 = NULL; ret->indexed_type = NULL; ret->annotations = NULL; return ret; } struct fauhdli * fauhdli_create( const char *parse_file, const char *trace_file, bool debug, const struct glue_vhdl_cb *callbacks, void *_cpssp ) { struct fauhdli *ret; bool r; if (callbacks->malloc != NULL) { ret = callbacks->malloc(sizeof(struct fauhdli)); } else { ret = malloc(sizeof(struct fauhdli)); } assert(ret != NULL); fauhdli_setup_callbacks(ret, callbacks); ret->container = NULL; ret->cleanup_ptrs = slset_create(NULL, ret->callbacks.malloc); ret->scheduler = vhdl_sched_create(&ret->callbacks); ret->signals = slset_create(NULL, ret->callbacks.malloc); ret->pending_stack_frames = slset_create(NULL, ret->callbacks.malloc); ret->processes = slset_create(NULL, ret->callbacks.malloc); ret->sim_time = 0; ret->debug = debug; ret->drivers = slset_create(NULL, ret->callbacks.malloc); ret->foreign_drivers = slset_create(NULL, ret->callbacks.malloc); ret->foreign_g_array_params.base.pointer = NULL; ret->foreign_g_array_params.left = 0; ret->foreign_g_array_params.left_set = false; ret->foreign_g_array_params.right = 0; ret->foreign_g_array_params.right_set = false; ret->foreign_g_array_params.direction = 0; ret->foreign_g_array_params.direction_set = false; ret->foreign_g_array_params.element_type = NULL; ret->foreign_g_array_params.formal_name = NULL; ret->foreign_mode = FOREIGN_MODE_COMPONENT; ret->wakeup_scheduled = false; ret->trace_list = NULL; assert(_cpssp != NULL); /* FIXME type should be opaque to us. */ ret->glue_vhdl = _cpssp; if (trace_file != NULL) { ret->tracer = trace_create(trace_file, callbacks); } else { ret->tracer = NULL; } r = fauhdli_parse(ret, parse_file); if (! r) { assert(0); return ret; } return ret; } void fauhdli_destroy(struct fauhdli *instance) { assert(instance != NULL); assert(instance->cleanup_ptrs != NULL); if (instance->container != NULL) { fauhdli_destroy_container(instance->container, &instance->callbacks); } fauhdli_kernel_destroy(instance); slset_destroy(instance->pending_stack_frames, instance->callbacks.free); slset_destroy(instance->drivers, instance->callbacks.free); slset_destroy(instance->foreign_drivers, instance->callbacks.free); slset_destroy_data(instance->cleanup_ptrs, instance->callbacks.free); fauhdli_destroy_signals(instance->signals, &instance->callbacks); vhdl_sched_destroy(instance->scheduler, &instance->callbacks); slset_destroy(instance->processes, instance->callbacks.free); if (instance->tracer != NULL) { trace_destroy(instance->tracer, &instance->callbacks); } instance->callbacks.free(instance); } void fauhdli_init( struct fauhdli *instance, const char *top_entity ) { if (top_entity == NULL) { instance->callbacks.log( FAUHDLI_LOG_WARNING, "fauhdli", __func__, "Top entity not specified!\n"); } fauhdli_resolve_symbols(instance); fauhdli_kernel_init(instance, top_entity); } const struct annotation_spec * fauhdli_find_annotation(const char *name, const struct slist *annotations) { struct slist_entry *i; if (annotations == NULL) { return NULL; } for (i = annotations->first; i != NULL; i = i->next) { const struct annotation_spec *spec = (const struct annotation_spec *)i->data; if (strcmp(spec->name, name) == 0) { return spec; } } return NULL; } void fauhdli_set_driver( struct fauhdli *instance, void *_drv, union fauhdli_value value ) { struct driver *drv = (struct driver *)_drv; int64_t t; /* set driver value */ assert(instance->callbacks.time_virt != NULL); t = (int64_t)instance->callbacks.time_virt(); assert(0 <= t); driver_update(drv, value, t, &instance->callbacks); /* kernel already running? */ if (instance->wakeup_scheduled) { return; } /* schedule a delta cycle */ assert(instance->callbacks.time_call_delete != NULL); assert(instance->callbacks.time_call_at != NULL); instance->callbacks.time_call_delete( fauhdli_kernel_simulation_cycle, instance); instance->callbacks.time_call_at( t, fauhdli_kernel_simulation_cycle, instance); instance->wakeup_scheduled = true; } fauhdlc-20130704/interpreter/vhdl_sched.h0000664000175000017500000000412311261375216017625 0ustar potyrapotyra/* $Id: vhdl_sched.h 4798 2009-10-02 13:05:18Z potyra $ * * Scheduler for VHDL processes. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __VHDL_SCHED_H_INCLUDED #define __VHDL_SCHED_H_INCLUDED #include "slset.h" #include #include "fauhdli.h" /** scheduler instance */ struct vhdl_sched { /* FIXME: eventually use a map/hash_map to do a quick lookup between * vhdl process pointer and vhdl_sched_process pointer? */ /** queue of runnable processes */ struct slset *run_q; /** queue of sleeping processes */ struct slset *wait_q; }; extern struct vhdl_sched * vhdl_sched_create(const struct glue_vhdl_cb *callbacks); extern void vhdl_sched_destroy( struct vhdl_sched *sched, const struct glue_vhdl_cb *callbacks ); /** add a process to the list of runnable processes. * @param sched scheduler instance. * @param s process instance. * @param run function to be called when process is run. * @param callbacks callbacks (for malloc) */ extern void vhdl_sched_add_process( struct vhdl_sched *sched, void *s, void (*run)(void *), const char *name, const struct glue_vhdl_cb *callbacks ); /** run all processes in the run_q, then return. * @param sched scheduler instance. */ extern void vhdl_sched_run( struct vhdl_sched *sched, const struct glue_vhdl_cb *callbacks ); /** check, if there are runnable processes. * @param sched scheduler instance. * @return true, if processes are in runnable state, false otherwise. */ extern bool vhdl_sched_has_runnable(struct vhdl_sched *sched); /** wakeup process s and put it in the runnable queue. * @param sched scheduler instance * @param s pointer of process instance * @param callbacks callbacks (for malloc -> slset) */ extern void vhdl_sched_wakeup( struct vhdl_sched *sched, void *s, const struct glue_vhdl_cb *callbacks ); #endif /* __SCHEDULER_H_INCLUDED */ fauhdlc-20130704/interpreter/kernel.c0000664000175000017500000020021111502676455017000 0ustar potyrapotyra/* $Id: kernel.c 5080 2010-12-17 15:09:33Z potyra $ * * Interpreter kernel. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "kernel.h" #include "signals.h" #include #include #include #include "glue-log.h" #include "slset.h" #include "mangle_names.h" #include "trace.h" #include "glue-main.h" #include #include "log.h" #define ARRAY_SIZE(t) (sizeof t / sizeof(t[0])) #if 1 /* kernel debugging enabled */ #define kernel_debug(instance, fmt, ...) (\ instance->callbacks.log(\ FAUHDLI_LOG_DEBUG, \ "fauhdli", \ __func__, \ fmt, \ __VA_ARGS__)\ ) #else /* kernel debugging disabled */ #define kernel_debug(fmt, ...) () #endif /* kernel debugging switch */ /** layout of one stack entry */ struct stack_frame { /** raw data of the stack frame */ void *data; /** transfer data of the stack frame */ void *transfer_data; /** link to parent stack entry */ struct stack_frame *parent; /** link to static parent stack entry */ struct stack_frame *static_parent; /** stored return address */ const struct slist_entry *return_address; /** stack frame for an upcoming function call * (initializied by begintrans) */ struct stack_frame *transfer; /** evil hack: store last transfer stack there */ struct stack_frame *last_transfer; /** nesting level of currently executed function */ unsigned int nesting_level; /** for foreign stack related transactions, recalled id (if any) */ unsigned int foreign_id; /** name of the stack frame (can be used to construct instance name) */ const char *name; /** pointer to allocated virtual registers */ union fauhdli_value *vregs; }; /** state of one process */ struct fauhdli_process { /** currently evaluated opcode (aka program counter) */ const struct slist_entry *pc; /** link back to instance (to obtain registers) */ struct fauhdli *instance; /** current stack entry */ struct stack_frame *stack; /** sensitivity set of the process (shadow copy of selected signals) */ struct slset *sensitivities; /** time of next event */ universal_integer next_event; /** debugging only: name of process */ const char *name; }; static void fauhdli_kernel_execute(struct fauhdli_process *s); /* ---------------- tracing related ----------------------- */ /** determine the display size out of annotations. * @param annotations list of annotations, maybe NULL. * @return annotated display size, or -1 if not found. */ static int fauhdli_get_display_size(const struct slist *annotations) { const struct annotation_spec *spec; spec = fauhdli_find_annotation("display_size", annotations); if (spec == NULL) { return -1; } return spec->int_value; } static const char * fauhdli_get_display_type(const struct slist *annotations) { const struct annotation_spec *spec; spec = fauhdli_find_annotation("display", annotations); if (spec == NULL) { return NULL; } return spec->string_value; } static enum type_kind fauhdli_get_basic_type(const struct type_element *te) { assert(te->elem_count == te->elements); assert(te->type != NULL); if (strcmp("universal_integer", te->type->name) == 0) { return TYPE_INT; } if (strcmp("universal_real", te->type->name) == 0) { return TYPE_FLOAT; } if (strcmp("__pointer__", te->type->name) == 0) { return TYPE_POINTER; } /* only reached, if not a composite type, but then the structures * are bogus! */ assert(false); return TYPE_INT; } /* return false if it is a simple array or non-composite type. * true, if it is an array of a record or something similar complex. */ static bool fauhdli_is_complex_composite(const struct type_element *te) { assert(te->elem_count != -1); return te->elem_count != te->elements; } static void fauhdli_trace_data( struct fauhdli *instance, const struct data_definition *data, const void *set_ptr ) { enum type_kind basic_type; const char *sig_loc; const char *display_type; int display_size; switch (data->storage) { case STORAGE_SIGNAL: break; default: /* not supported right now */ return; } /* it's a signal! */ assert(data->type != NULL); assert(data->type->type != NULL); if (fauhdli_is_complex_composite(data->type)) { instance->callbacks.log( FAUHDLI_LOG_WARNING, "fauhdli", "kernel", "Tracing composite signal %s not (yet) supported\n", data->name); return; } sig_loc = (const char *)set_ptr + data->offset; basic_type = fauhdli_get_basic_type(data->type); display_size = fauhdli_get_display_size(data->annotations); display_type = fauhdli_get_display_type(data->annotations); trace_add_signal(instance->tracer, (const union fauhdli_value*)(const void *)sig_loc, data->name, basic_type, display_size, display_type, &instance->callbacks, data->type->elements); } static void fauhdli_trace_segment( struct fauhdli *instance, const struct slist *seg_defs, const void *segment ) { const struct slist_entry *i; for (i = seg_defs->first; i != NULL; i = i->next) { const struct data_definition *d = (const struct data_definition *)i->data; fauhdli_trace_data(instance, d, segment); } } /* ---------- misc. helper functions ----------------------- */ #if 0 /* enable for debugging stack frames, currently unused */ static void fauhdli_kernel_debug_stack_r( struct stack_frame *sf, unsigned int depth, bool static_parent ) { char buf[2048]; memset(buf, ' ', sizeof(buf) - 1); assert(depth * 4 < sizeof(buf)); buf[depth * 4] = '\0'; if (static_parent) { kernel_debug("%sstatic parent=%p\n", buf, sf); } else { kernel_debug("%sstack=%p\n", buf, sf); } if (sf == NULL) { return; } fauhdli_kernel_debug_stack_r(sf->parent, depth + 1, false); fauhdli_kernel_debug_stack_r(sf->static_parent, depth + 1, true); } static void __attribute__((__used__)) fauhdli_kernel_debug_stack(struct stack_frame *sf) { kernel_debug("*************** STACK %p *************\n", sf); fauhdli_kernel_debug_stack_r(sf, 0, false); } #endif static struct fauhdli_process * process_create(const struct glue_vhdl_cb *callbacks) { struct fauhdli_process *process; process = callbacks->malloc(sizeof(struct fauhdli_process)); assert(process != NULL); process->pc = NULL; process->instance = NULL; process->stack = NULL; process->sensitivities = slset_create(NULL, callbacks->malloc); process->next_event = INT64_MAX; process->name = NULL; return process; } static void process_destroy(struct fauhdli_process *p) { slset_destroy(p->sensitivities, p->instance->callbacks.free); p->instance->callbacks.free(p); } static void kernel_add_sensitivity(struct fauhdli_process *s, struct signal *sig) { slset_add(s->sensitivities, sig, s->instance->callbacks.malloc); } static void kernel_add_timeout(struct fauhdli_process *s, universal_integer timeout) { assert(s->instance->sim_time < timeout); s->next_event = timeout; } static void fauhdli_kernel_destroy_stack_frame( struct stack_frame *sf, const struct glue_vhdl_cb *callbacks ) { if (sf == NULL) { return; } if (sf->data != NULL) { callbacks->free(sf->data); } if (sf->transfer_data != NULL) { callbacks->free(sf->transfer_data); } if (sf->vregs != NULL) { callbacks->free(sf->vregs); } callbacks->free(sf); } static void fauhdli_kernel_proc_run(void *_proc) { struct fauhdli_process *proc = (struct fauhdli_process *)_proc; fauhdli_kernel_execute(proc); } /* ---------- functions modifiy the internal state --------- */ static void inc_pc(struct fauhdli_process *s) { s->pc = s->pc->next; assert(s->pc != NULL); } /* ---------- functions to create data types/segments ------ */ /** create a basic data element (i.e. non-composite). * @param initializer initializer from surrounding data. For each data * element, this will be advanced. */ static size_t create_basic_data( struct fauhdli_process *s, const struct type_element *elem, const struct code_container *resolver, char *dest, enum storage_kind storage, const char *name, const char *foreign_val, bool foreign_to_vhdl, struct slist_entry **initializer ) { union fauhdli_value init; assert(initializer != NULL); if (*initializer != NULL) { const struct operand *imm_init = (const struct operand*)(*initializer)->data; assert(imm_init->kind == OPERAND_IMMEDIATE); init = imm_init->bytype.immediate; *initializer = (*initializer)->next; } else { if (s->instance->debug) { s->instance->callbacks.log( FAUHDLI_LOG_WARNING, "fauhdli", "kernel", "Basic type %s defines no initial value!\n", elem->name); } init.univ_int = 0; } /* "foreign" is only interesting when creating signals * Variables that are foreign are created regularly, * however signals *additionally* create a corresponding hidden * driver. */ switch (storage) { case STORAGE_VARIABLE: *(union fauhdli_value*)(void *)dest = init; break; case STORAGE_DRIVER: { struct driver **drv = (struct driver **)(void *)dest; *drv = driver_create(init, &s->instance->callbacks); slset_add( s->instance->drivers, *drv, s->instance->callbacks.malloc); break; } case STORAGE_SIGNAL: { struct signal **sig = (struct signal **)(void *)dest; *sig = signal_create(init, foreign_val, s->instance, name, resolver ); slset_add( s->instance->signals, *sig, s->instance->callbacks.malloc); if (foreign_to_vhdl) { signal_connect_foreign_in_driver( *sig, s->instance, s->instance->drivers); } break; } } return sizeof(union fauhdli_value); } /** create a data by type definition * (TODO) * @param initializer initializer of data element. * @param name name of the data type (for debugging) * @param foreign_val mapped to foreign type name (or NULL if not * foreign) * @param foreign_to_vhdl true, if a foreign signal is read from * VHDL context, false otherwise. */ static size_t create_data_by_type( struct fauhdli_process *s, const struct type_element *elem, const struct code_container *resolver, struct slist_entry **initializer, char *dest, enum storage_kind storage, const char *name, const char *foreign_val, bool foreign_to_vhdl ) { const struct type_declaration *t; struct slist_entry *i; size_t ret = 0; size_t sz; universal_integer cnt; char buf[8192]; int n; t = elem->type; assert(t != NULL); assert(initializer != NULL); if (t->elements != NULL) { cnt = 0; /* not a basic type, traverse to elements */ for (i = t->elements->first; i != NULL; i = i->next) { const struct type_element *te = (const struct type_element *)i->data; if (*initializer == NULL) { /* data doesn't have initial value, so use default value from type element */ initializer = &te->initial_list->first; } n = snprintf(buf, sizeof(buf), "%s__%" PRIi64, name, cnt); assert(n > 0); assert((size_t)n < sizeof(buf)); /* FIXME not handled yet */ assert(resolver == NULL); sz = create_data_by_type(s, te, NULL, initializer, dest, storage, buf, foreign_val, foreign_to_vhdl); dest += sz; ret += sz; cnt++; } return ret; } /* basic type */ assert(elem->elements != -1); for (cnt = 0; cnt < elem->elements; cnt++) { n = snprintf(buf, sizeof(buf), "%s__%" PRIi64, name, cnt); assert(n > 0); assert((size_t)n < sizeof(buf)); sz = create_basic_data(s, elem, resolver, dest, storage, buf, foreign_val, foreign_to_vhdl, initializer); dest += sz; ret += sz; } return ret; } /** @param current process instance. * @param data data definition to create * @parem dest destination pointer in stack space. * @param instance_prefix instance name prefix to use for data. * @return size of generate data entry. */ static size_t create_data( struct fauhdli_process *s, const struct data_definition *data, char *dest, const char *instance_prefix ) { size_t ret; const struct annotation_spec *spec; const char *foreign_val = NULL; bool foreign_to_vhdl = false; char buf[8192]; char *n; struct slist_entry *initializer; assert(data != NULL); assert(dest != NULL); assert(data->type != NULL); spec = fauhdli_find_annotation("foreign", data->annotations); if (spec != NULL) { foreign_val = spec->string_value; } if (foreign_val != NULL) { spec = fauhdli_find_annotation("read", data->annotations); if (spec != NULL) { assert(spec->int_value == 1); foreign_to_vhdl = true; } } n = data->name; if (*instance_prefix != '\0') { int i; i = snprintf(buf, sizeof(buf), "%s%s", instance_prefix, data->name); assert(i > 0); assert(i < sizeof(buf)); n = buf; } initializer = data->type->initial_list->first; ret = create_data_by_type(s, data->type, data->resolver.container, &initializer, dest, data->storage, n, foreign_val, foreign_to_vhdl); assert(ret == data->storage_size); return data->storage_size; } static void * create_data_segment( struct fauhdli_process *s, const struct slist *data_segment, size_t storage_size, const char *instance_prefix ) { void *ret; char *d; struct slist_entry *i; ret = s->instance->callbacks.malloc(storage_size); assert(ret != NULL); d = (char *)ret; for (i = data_segment->first; i != NULL; i = i->next) { size_t sz; struct data_definition *elem = (struct data_definition *)i->data; sz = create_data(s, elem, d, instance_prefix); d += sz; } assert(d - (char *)ret >= 0); assert((size_t)(d - (char *)ret) == storage_size); return ret; } static size_t get_stack_name_r(const struct stack_frame *s, char *buf, size_t sz) { size_t ret; if (s == NULL) { ret = snprintf(buf, sz, "__c_"); assert(ret < sz); return ret; } ret = get_stack_name_r(s->parent, buf, sz); sz -= ret; buf += ret; assert(sz > 0); if (s->name == NULL) { return ret; } if (strlen(s->name) == 0) { return ret; } ret += snprintf(buf, sz, "%s__c_", s->name); return ret; } static const char * get_stack_name(const struct stack_frame *s) { static char buf[8192]; buf[0] = '\0'; get_stack_name_r(s, buf, sizeof(buf)); return buf; } static struct stack_frame * create_stack_frame( struct fauhdli_process *s, const struct code_container *container, struct stack_frame *parent, struct stack_frame *static_parent, const char *name ) { struct stack_frame *sf; const char *instance_name; assert(container != NULL); sf = s->instance->callbacks.malloc(sizeof(struct stack_frame)); assert(sf != NULL); sf->parent = parent; sf->static_parent = static_parent; sf->return_address = NULL; sf->transfer = NULL; sf->foreign_id = 0; sf->name = name; sf->vregs = s->instance->callbacks.malloc( sizeof(union fauhdli_value) * container->num_vregs); assert(sf->vregs != NULL); if (static_parent != NULL) { sf->nesting_level = static_parent->nesting_level + 1; } else { sf->nesting_level = 1; /* 1 -> top stack frame */ } instance_name = get_stack_name(sf); if (container->stack_segment != NULL) { sf->data = create_data_segment( s, container->stack_segment, container->stack_size, instance_name); } else { sf->data = NULL; } if (container->transfer_segment != NULL) { sf->transfer_data = create_data_segment( s, container->transfer_segment, container->transfer_size, "transfer__c_" /* FIXME? */); } else { sf->transfer_data = NULL; } return sf; } static struct stack_frame * create_foreign_stack( struct stack_frame *parent, unsigned int foreign_id, const struct glue_vhdl_cb *callbacks ) { /* TODO (idea) actually, it might even be possible to use the * transfer segment as mechanism between fauhdli * and foreign components. */ struct stack_frame *sf; sf = callbacks->malloc(sizeof(struct stack_frame)); assert(sf != NULL); sf->parent = parent; sf->static_parent = NULL; sf->return_address = NULL; sf->transfer = NULL; sf->foreign_id = foreign_id; sf->nesting_level = 0; sf->data = NULL; return sf; } /* -------------- functions related to operands ------------ */ static const struct slist_entry * fetch_target(struct operand *target) { assert(target != NULL); assert(target->kind == OPERAND_TARGET); assert(target->bytype.target.ref != NULL); return target->bytype.target.ref; } static const struct code_container * fetch_target_container(struct operand *target) { assert(target != NULL); assert(target->kind == OPERAND_REFERENCE); assert(target->bytype.data.container != NULL); return target->bytype.data.container; } static void read_mem( const struct fauhdli_process *s, union fauhdli_value *ret, void *mem, enum type_kind type ) { switch (type) { case TYPE_INT: ret->univ_int = *(universal_integer*)mem; break; case TYPE_FLOAT: ret->univ_real = *(universal_real*)mem; break; case TYPE_POINTER: ret->pointer = *(void **)mem; break; } } static void write_mem( struct fauhdli_process *s, void *mem, union fauhdli_value val, enum type_kind type ) { switch (type) { case TYPE_INT: *(universal_integer*)mem = val.univ_int; break; case TYPE_FLOAT: *(universal_real*)mem = val.univ_real; break; case TYPE_POINTER: *(void **)mem = val.pointer; break; } } /** read the contents of a register. * @param s current process state. * @param ret value will be stored here. * @param reg register number * @param type type of register, only useful for debugging. */ static void read_register( const struct fauhdli_process *s, union fauhdli_value *ret, unsigned int reg, enum type_kind type ) { *ret = s->stack->vregs[reg]; } static void write_register( struct fauhdli_process *s, unsigned int reg, union fauhdli_value val, enum type_kind type ) { s->stack->vregs[reg] = val; } static void read_reference( const struct fauhdli_process *s, union fauhdli_value *ret, const struct data_definition *src ) { char *loc = NULL; struct stack_frame *stack = s->stack; assert(src != NULL); assert(stack != NULL); /* find correct stack segment by static_parent */ while (src->nesting_level < stack->nesting_level) { assert(stack->static_parent != NULL); stack = stack->static_parent; } switch (src->loc) { case SEGMENT_TRANSFER: assert(stack->transfer_data != NULL); loc = (char *)stack->transfer_data + src->offset; break; case SEGMENT_STACK: assert(stack->data != NULL); loc = (char *)stack->data + src->offset; break; } ret->pointer = loc; } static void read_operand( const struct fauhdli_process *s, union fauhdli_value *ret, const struct operand *src ) { union fauhdli_value ind; assert(ret != NULL); assert(src != NULL); switch (src->kind) { case OPERAND_REGISTER: read_register(s, ret, src->bytype.reg, src->type); break; case OPERAND_IMMEDIATE: *ret = src->bytype.immediate; break; case OPERAND_INDIRECT: read_register(s, &ind, src->bytype.reg, TYPE_POINTER); read_mem(s, ret, ind.pointer, src->type); break; case OPERAND_REFERENCE: assert(src->type == TYPE_POINTER); read_reference(s, ret, src->bytype.data.ref); break; case OPERAND_TARGET: /* FIXME: valid? */ assert(0); break; } } static void write_operand( struct fauhdli_process *s, struct operand *dst, union fauhdli_value value ) { union fauhdli_value ind; assert(dst != NULL); switch (dst->kind) { case OPERAND_REGISTER: write_register(s, dst->bytype.reg, value, dst->type); break; case OPERAND_INDIRECT: read_register(s, &ind, dst->bytype.reg, TYPE_POINTER); write_mem(s, ind.pointer, value, dst->type); break; case OPERAND_REFERENCE: /* doesn't make sense (reference is a pointer by name, so * it is some kind of immediate) */ assert(0); break; case OPERAND_TARGET: /* mustn't write into text segment */ assert(0); break; case OPERAND_IMMEDIATE: /* mustn't write to immedate */ assert(0); break; } } /** compare two operand values. * @param v1 first operand value to compare * @param v2 second operand value to compare. * @return 0 if equal, -1 if v1 < v2 and 1 if v1 > v2 */ static int compare_values( union fauhdli_value v1, union fauhdli_value v2, enum type_kind kind ) { switch (kind) { case TYPE_INT: if (v1.univ_int == v2.univ_int) { return 0; } if (v1.univ_int < v2.univ_int) { return -1; } return 1; case TYPE_FLOAT: if (v1.univ_real == v2.univ_real) { return 0; } if (v1.univ_real < v2.univ_real) { return -1; } return 1; case TYPE_POINTER: if (v1.pointer == v2.pointer) { return 0; } if (v1.pointer < v2.pointer) { return -1; } return 1; } /* not reached */ assert(0); return 0; } /* -------------- functions for evaluating opcodes --------- */ static void eval_jmp(struct fauhdli_process *s, const struct opcode *jmp) { assert(jmp->kind == OPCODE_JMP); assert(jmp->op2 == NULL); assert(jmp->op3 == NULL); assert(jmp->label == NULL); s->pc = fetch_target(jmp->op1); } static void eval_mov(struct fauhdli_process *s, const struct opcode *mov) { union fauhdli_value val; assert(mov != NULL); assert(mov->op3 == NULL); assert(mov->label == NULL); read_operand(s, &val, mov->op1); write_operand(s, mov->op2, val); inc_pc(s); } static void eval_add(struct fauhdli_process *s, const struct opcode *add) { union fauhdli_value op1; union fauhdli_value op2; union fauhdli_value res; res.univ_int = 0; assert(add->op1 != NULL); assert(add->op2 != NULL); assert(add->op3 != NULL); assert(add->op1->type == add->op2->type); assert(add->op1->type == add->op3->type); read_operand(s, &op1, add->op1); read_operand(s, &op2, add->op2); switch (add->op1->type) { case TYPE_INT: res.univ_int = op1.univ_int + op2.univ_int; break; case TYPE_FLOAT: res.univ_real = op1.univ_real + op2.univ_real; break; case TYPE_POINTER: /* currently no use to add two pointers */ assert(0); break; } write_operand(s, add->op3, res); inc_pc(s); } static void eval_sub(struct fauhdli_process *s, const struct opcode *sub) { union fauhdli_value op1; union fauhdli_value op2; union fauhdli_value res; res.univ_int = 0; assert(sub->op1 != NULL); assert(sub->op2 != NULL); assert(sub->op3 != NULL); assert(sub->op1->type == sub->op2->type); assert(sub->op1->type == sub->op3->type); read_operand(s, &op1, sub->op1); read_operand(s, &op2, sub->op2); switch (sub->op1->type) { case TYPE_INT: res.univ_int = op1.univ_int - op2.univ_int; break; case TYPE_FLOAT: res.univ_real = op1.univ_real - op2.univ_real; break; case TYPE_POINTER: /* currently no use to subtract two pointers */ assert(0); break; } write_operand(s, sub->op3, res); inc_pc(s); } static void eval_imul(struct fauhdli_process *s, const struct opcode *imul) { union fauhdli_value op1; union fauhdli_value op2; union fauhdli_value res; res.univ_int = 0; assert(imul->op1 != NULL); assert(imul->op2 != NULL); assert(imul->op3 != NULL); assert(imul->op1->type == imul->op2->type); assert(imul->op1->type == imul->op3->type); read_operand(s, &op1, imul->op1); read_operand(s, &op2, imul->op2); switch (imul->op1->type) { case TYPE_INT: res.univ_int = op1.univ_int * op2.univ_int; break; case TYPE_FLOAT: res.univ_real = op1.univ_real * op2.univ_real; break; case TYPE_POINTER: /* currently no use to multiply two pointers */ assert(0); break; } write_operand(s, imul->op3, res); inc_pc(s); } static void eval_div(struct fauhdli_process *s, const struct opcode *op_div) { union fauhdli_value op1; union fauhdli_value op2; union fauhdli_value res; res.univ_int = 0; assert(op_div->op1 != NULL); assert(op_div->op2 != NULL); assert(op_div->op3 != NULL); assert(op_div->op1->type == op_div->op2->type); assert(op_div->op1->type == op_div->op3->type); read_operand(s, &op1, op_div->op1); read_operand(s, &op2, op_div->op2); switch (op_div->op1->type) { case TYPE_INT: res.univ_int = op1.univ_int / op2.univ_int; break; case TYPE_FLOAT: res.univ_real = op1.univ_real / op2.univ_real; break; case TYPE_POINTER: /* currently no use to divide two pointers */ assert(0); break; } write_operand(s, op_div->op3, res); inc_pc(s); } static void eval_je(struct fauhdli_process *s, const struct opcode *je) { union fauhdli_value cmp1; union fauhdli_value cmp2; int cmp; assert(je->op1 != NULL); assert(je->op2 != NULL); assert(je->op3 != NULL); assert(je->op1->type == je->op2->type); read_operand(s, &cmp1, je->op1); read_operand(s, &cmp2, je->op2); cmp = compare_values(cmp1, cmp2, je->op1->type); if (cmp == 0) { /* branch taken */ s->pc = fetch_target(je->op3); } else { /* branch not taken */ inc_pc(s); } } static void eval_jb(struct fauhdli_process *s, const struct opcode *jb) { union fauhdli_value cmp1; union fauhdli_value cmp2; int cmp; assert(jb->op1 != NULL); assert(jb->op2 != NULL); assert(jb->op3 != NULL); assert(jb->op1->type == jb->op2->type); read_operand(s, &cmp1, jb->op1); read_operand(s, &cmp2, jb->op2); cmp = compare_values(cmp1, cmp2, jb->op1->type); if (cmp == -1) { /* branch taken */ s->pc = fetch_target(jb->op3); } else { /* branch not taken */ inc_pc(s); } } static void eval_jne(struct fauhdli_process *s, const struct opcode *jne) { union fauhdli_value cmp1; union fauhdli_value cmp2; int cmp; assert(jne->op1 != NULL); assert(jne->op2 != NULL); assert(jne->op3 != NULL); assert(jne->op1->type == jne->op2->type); read_operand(s, &cmp1, jne->op1); read_operand(s, &cmp2, jne->op2); cmp = compare_values(cmp1, cmp2, jne->op1->type); if (cmp != 0) { /* branch taken */ s->pc = fetch_target(jne->op3); } else { /* branch not taken */ inc_pc(s); } } static void eval_jbe(struct fauhdli_process *s, const struct opcode *jbe) { union fauhdli_value cmp1; union fauhdli_value cmp2; int cmp; assert(jbe->op1 != NULL); assert(jbe->op2 != NULL); assert(jbe->op3 != NULL); assert(jbe->op1->type == jbe->op2->type); read_operand(s, &cmp1, jbe->op1); read_operand(s, &cmp2, jbe->op2); cmp = compare_values(cmp1, cmp2, jbe->op1->type); if (cmp != 1) { /* branch taken */ s->pc = fetch_target(jbe->op3); } else { /* branch not taken */ inc_pc(s); } } static void eval_foreign_comp_init( struct fauhdli *instance, unsigned int comp_id, const char *comp_name ) { assert(instance->callbacks.comp_init != NULL); instance->callbacks.comp_init(instance->glue_vhdl, comp_id); } static void eval_foreign_arch_init( struct fauhdli *instance, unsigned int comp_id, const char *comp_name ) { assert(instance->callbacks.arch_init != NULL); instance->callbacks.arch_init(instance->glue_vhdl, comp_id); } static void eval_foreign_call( struct fauhdli *instance, const struct stack_frame *foreign_stack, const char *foreign_val, const char *target ) { if (strcmp(foreign_val, "entity") == 0) { eval_foreign_comp_init(instance, foreign_stack->foreign_id, target); } else if (strcmp(foreign_val, "architecture") == 0) { eval_foreign_arch_init(instance, foreign_stack->foreign_id, target); } else if (strcmp(foreign_val, "procedure") == 0) { assert(instance->callbacks.proc_call != NULL); instance->callbacks.proc_call(instance->glue_vhdl, target); } else { assert(0); } } static void eval_call(struct fauhdli_process *s, const struct opcode *call) { const struct code_container *target; const struct annotation_spec *spec = fauhdli_find_annotation("foreign", call->annotations); assert(call->op1 != NULL); assert(call->op2 == NULL); assert(call->op3 == NULL); assert(s->stack != NULL); assert(s->stack->transfer != NULL); if (spec != NULL) { eval_foreign_call(s->instance, s->stack->transfer, spec->string_value, call->op1->bytype.data.name); inc_pc(s); return; } /* should have been set by begintrans */ assert(s->stack->transfer->static_parent != NULL); assert(s->stack->transfer->parent != NULL); assert(s->stack->transfer->transfer == NULL); inc_pc(s); s->stack->transfer->return_address = s->pc; s->stack = s->stack->transfer; target = fetch_target_container(call->op1); assert(target->text_segment != NULL); s->pc = target->text_segment->first; } static void eval_proc(struct fauhdli_process *s, const struct opcode *proc) { const struct code_container *target; struct fauhdli_process *process; assert(proc->op1 != NULL); assert(proc->op2 == NULL); assert(proc->op3 == NULL); assert(s->stack != NULL); assert(s->stack->transfer != NULL); /* should have been set by begintrans */ assert(s->stack->transfer->static_parent != NULL); assert(s->stack->transfer->parent != NULL); assert(s->stack->transfer->transfer == NULL); s->stack->transfer->return_address = NULL; target = fetch_target_container(proc->op1); assert(target->text_segment != NULL); process = process_create(&s->instance->callbacks); process->name = target->name; process->instance = s->instance; process->stack = s->stack->transfer; process->pc = target->text_segment->first; vhdl_sched_add_process(s->instance->scheduler, process, fauhdli_kernel_proc_run, target->name, &s->instance->callbacks); slset_add( s->instance->processes, process, s->instance->callbacks.malloc); inc_pc(s); } static unsigned int eval_create_foreign_component( struct fauhdli *instance, const char *comp_name, const char *type, enum foreign_mode_e foreign_mode ) { unsigned int comp_id = 0; static char demangled[2048]; int ret; ret = demangle_name(comp_name, demangled, sizeof(demangled)); assert(ret >= 0); assert((size_t)ret < sizeof(demangled)); switch (foreign_mode) { case FOREIGN_MODE_COMPONENT: assert(instance->callbacks.comp_create != NULL); comp_id = instance->callbacks.comp_create( instance->glue_vhdl, type, demangled); break; case FOREIGN_MODE_ARCHITECTURE: assert(instance->callbacks.arch_create != NULL); comp_id = instance->callbacks.arch_create( instance->glue_vhdl, type, demangled); break; } return comp_id; } /** evaluate a foreign begintrans opcode. * @param instance interpreter instance. * @param container_name name of the container (reference name of op1) * @param kind kind of foreign begintrans (foreign annotation value) * @param stack current stack frame for instance prefix * @param foreign_mode will get set according to annotation * @param name instance name of the componenent * @return optional foreign_id, that will be stored in foreign_id of * stack_frame. */ static unsigned int eval_foreign_begintrans( struct fauhdli *instance, const char *container_name, const char *kind, const struct stack_frame *stack, enum foreign_mode_e *foreign_mode, const char *name ) { unsigned int ret; if (strcmp(kind, "entity") == 0) { char buf[8192]; const char *n; n = get_stack_name(stack); if (*n != '\0') { int r; r = snprintf(buf, sizeof(buf), "%s%s", n, name); assert(r >= 0); assert(r < sizeof(buf)); n = buf; } else { n = name; } *foreign_mode = FOREIGN_MODE_COMPONENT; ret = eval_create_foreign_component( instance, n, container_name, FOREIGN_MODE_COMPONENT); return ret; } else if (strcmp(kind, "architecture") == 0) { const char *n; size_t sz; char buf[8192]; n = get_stack_name(stack); strncpy(buf, n, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; /* foreign architectures are created from within the * architecture. The stack name will hence be the actually * instance name ending with a ':', and the name is the * name of the architecture (still mangled here though). * Turn this back into the instance name by removing the last * ':'. */ sz = strlen(buf); assert(sz > 4); /* should end with (mangled) "__c_" */ assert(buf[sz - 1] == '_'); assert(buf[sz - 2] == 'c'); assert(buf[sz - 3] == '_'); assert(buf[sz - 4] == '_'); buf[sz - 4] = '\0'; *foreign_mode = FOREIGN_MODE_ARCHITECTURE; ret = eval_create_foreign_component( instance, buf, container_name, FOREIGN_MODE_ARCHITECTURE); return ret; } else if (strcmp(kind, "procedure") == 0) { /* nothing to do for a procedure... or should this be * proxied to glue-vhdl as well? */ return 0; } else { /* TODO */ assert(0); } /* not reached */ return 0; } static void eval_begintrans( struct fauhdli_process *s, const struct opcode *begintrans ) { unsigned int i; const struct code_container *target; struct stack_frame *static_parent; const struct annotation_spec *spec = fauhdli_find_annotation("foreign", begintrans->annotations); struct stack_frame *last_transfer; assert(begintrans->op1 != NULL); assert(begintrans->op2 != NULL); assert(begintrans->op3 == NULL); /* FIXME evil hack to work around broken code generator */ last_transfer = s->stack->transfer; s->stack->transfer = NULL; assert(s->stack->transfer == NULL); assert(begintrans->op2->kind == OPERAND_REFERENCE); if (spec != NULL) { unsigned int id; /* don't create any stack frame for foreign entities. */ assert(spec->string_value != NULL); id = eval_foreign_begintrans(s->instance, begintrans->op1->bytype.data.name, spec->string_value, s->stack, &s->instance->foreign_mode, begintrans->op2->bytype.data.name); s->stack->transfer = create_foreign_stack( s->stack, id, &s->instance->callbacks); s->stack->transfer->last_transfer = last_transfer; inc_pc(s); return; } target = fetch_target_container(begintrans->op1); static_parent = s->stack; /* it's only possible to jump one level deeper, stay on the same level * or to jump upwards. */ assert(target->nesting_level - 1 <= s->stack->nesting_level); for (i = target->nesting_level; i <= s->stack->nesting_level; i++) { assert(static_parent != NULL); static_parent = static_parent->static_parent; } s->stack->transfer = create_stack_frame(s, target, s->stack, static_parent, begintrans->op2->bytype.data.name); assert(s->stack->transfer->nesting_level == target->nesting_level); s->stack->transfer->last_transfer = last_transfer; inc_pc(s); } static void eval_foreign_endtrans( struct stack_frame *sf, const struct glue_vhdl_cb *callbacks ) { callbacks->free(sf); } static void eval_endtrans(struct fauhdli_process *s, const struct opcode *endtrans) { union fauhdli_value fs; const struct annotation_spec *spec = fauhdli_find_annotation("foreign", endtrans->annotations); struct stack_frame *tmp; assert(endtrans->op1 != NULL); assert(endtrans->op2 != NULL); assert(endtrans->op3 == NULL); assert(s->stack->transfer != NULL); assert(endtrans->op2->type == TYPE_INT); read_operand(s, &fs, endtrans->op2); if (spec != NULL) { /* for foreign stack operations, always free the stack * frame again. */ eval_foreign_endtrans( s->stack->transfer, &s->instance->callbacks); s->stack->transfer = s->stack->transfer->last_transfer; inc_pc(s); return; } tmp = s->stack->transfer->last_transfer; if (fs.univ_int != 0) { fauhdli_kernel_destroy_stack_frame( s->stack->transfer, &s->instance->callbacks); } else { slset_add( s->instance->pending_stack_frames, s->stack->transfer, s->instance->callbacks.malloc); } s->stack->transfer = tmp; inc_pc(s); } /** setparam/foreign: set a port via glue-vhdl. * @param instance fauhdli instance. * @param comp_id stored id of the instantiated component via * begintrans. * @param sig signal (should be foreign!) * @param comp component name (entity name, not instantiation name) * @param port name of port of component. * @param foreign_mode_e do we instantiate a component or create * an architecture? */ static void eval_set_foreign_port( struct fauhdli *instance, unsigned int comp_id, struct signal *sig, const char *comp, const char *port, enum foreign_mode_e foreign_mode ) { assert(sig->is_foreign); switch (foreign_mode) { case FOREIGN_MODE_COMPONENT: assert(instance->callbacks.comp_port_connect != NULL); instance->callbacks.comp_port_connect( instance->glue_vhdl, comp_id, port, sig->foreign_id); break; case FOREIGN_MODE_ARCHITECTURE: assert(instance->callbacks.arch_port_connect != NULL); instance->callbacks.arch_port_connect( instance->glue_vhdl, comp_id, port, sig->foreign_id); break; } } static void eval_set_foreign_proc_param( struct fauhdli *instance, const char *proc, const char *param, union fauhdli_value value ) { assert(instance->callbacks.proc_set != NULL); instance->callbacks.proc_set(instance->glue_vhdl, proc, param, value); } /** FIXME that's a mess here. * there already is foreign_stack, and *that* should get * reused for proper calling into glue-vhdl, not a second * hidden stack like structure introduced in the fauhdli * instance. */ static void eval_set_foreign_generic( struct fauhdli *s, unsigned int comp_id, union fauhdli_value val, const char *comp, const char *generic, struct slist *annotations ) { const struct annotation_spec *is_bound; const struct annotation_spec *is_unconstraint; const struct annotation_spec *is_array = fauhdli_find_annotation("array", annotations); const struct annotation_spec *type = fauhdli_find_annotation("type", annotations); if ((is_array == NULL) || (is_array->int_value == 0)) { /* not an array */ assert(type != NULL); switch (s->foreign_mode) { case FOREIGN_MODE_COMPONENT: assert(s->callbacks.comp_generic_nonarray_set != NULL); s->callbacks.comp_generic_nonarray_set(s->glue_vhdl, comp_id, generic, val, type->string_value); break; case FOREIGN_MODE_ARCHITECTURE: assert(s->callbacks.arch_generic_nonarray_set != NULL); s->callbacks.arch_generic_nonarray_set(s->glue_vhdl, comp_id, generic, val, type->string_value); break; } return; } /* array */ is_unconstraint = fauhdli_find_annotation("unconstraint", annotations); if ((is_unconstraint == NULL) || (is_unconstraint->int_value == 0)) { /* constraint array */ /* FIXME */ assert(0); } if (comp_id != s->foreign_g_array_params.comp_id) { /* sanity check */ assert(s->foreign_g_array_params.base.pointer == NULL); assert(! s->foreign_g_array_params.left_set); assert(! s->foreign_g_array_params.right_set); s->foreign_g_array_params.comp_id = comp_id; } is_bound = fauhdli_find_annotation("bounds", annotations); if (! is_bound) { /* base pointer */ assert(type != NULL); assert(s->foreign_g_array_params.base.pointer == NULL); s->foreign_g_array_params.base = val; s->foreign_g_array_params.element_type = type->string_value; s->foreign_g_array_params.formal_name = generic; } else if (strcmp(is_bound->string_value, "l") == 0) { /* low bound */ assert(! s->foreign_g_array_params.left_set); s->foreign_g_array_params.left_set = true; s->foreign_g_array_params.left = val.univ_int; /* FIXME use only right bound! */ } else if ((strcmp(is_bound->string_value, "u") == 0) || (strcmp(is_bound->string_value, "r") == 0)) { /* right bound */ assert(! s->foreign_g_array_params.right_set); s->foreign_g_array_params.right_set = true; s->foreign_g_array_params.right = val.univ_int; } else if (strcmp(is_bound->string_value, "dir") == 0) { /* direction */ assert(! s->foreign_g_array_params.direction_set); s->foreign_g_array_params.direction_set = true; s->foreign_g_array_params.direction = val.univ_int; } else { /* must not happen */ assert(0); } if ( s->foreign_g_array_params.base.pointer != NULL && s->foreign_g_array_params.left_set && s->foreign_g_array_params.right_set && s->foreign_g_array_params.direction_set) { /* array parameter completely collected, flush to glue_vhdl */ universal_integer sz = ((s->foreign_g_array_params.right - s->foreign_g_array_params.left) * s->foreign_g_array_params.direction) + 1; if (sz < 0) { sz = 0; } switch (s->foreign_mode) { case FOREIGN_MODE_COMPONENT: assert(s->callbacks.comp_generic_array_set != NULL); s->callbacks.comp_generic_array_set( s->glue_vhdl, comp_id, s->foreign_g_array_params.formal_name, s->foreign_g_array_params.element_type, s->foreign_g_array_params.base, sz); break; case FOREIGN_MODE_ARCHITECTURE: assert(s->callbacks.arch_generic_array_set != NULL); s->callbacks.arch_generic_array_set( s->glue_vhdl, comp_id, s->foreign_g_array_params.formal_name, s->foreign_g_array_params.element_type, s->foreign_g_array_params.base, sz); break; } s->foreign_g_array_params.base.pointer = NULL; s->foreign_g_array_params.element_type = NULL; s->foreign_g_array_params.formal_name = NULL; s->foreign_g_array_params.left_set = false; s->foreign_g_array_params.right_set = false; s->foreign_g_array_params.direction_set = false; } } static void eval_foreign_setparam( struct fauhdli *s, const struct stack_frame *foreign_stack, const char *foreign_val, union fauhdli_value src, const char *component, const char *target, struct slist *annotations ) { /* FIXME why special case generics? */ /* FIXME that's all a complete and utter mess... * foreign generics should be known by FAUmachine, * in the same way as foreign procedures and * functions should be known! */ if (strcmp(foreign_val, "procedure") == 0) { eval_set_foreign_proc_param(s, component, target, src); } else if (strcmp(foreign_val, "port") == 0) { eval_set_foreign_port(s, foreign_stack->foreign_id, (struct signal *)src.pointer, component, target, s->foreign_mode); } else if (strcmp(foreign_val, "generic") == 0) { eval_set_foreign_generic(s, foreign_stack->foreign_id, src, component, target, annotations); } else { assert(0); } } static void eval_setparam(struct fauhdli_process *s, const struct opcode *setparam) { const struct code_container *container; union fauhdli_value src; char *loc; const struct annotation_spec *spec = fauhdli_find_annotation("foreign", setparam->annotations); assert(setparam->op1 != NULL); /* source */ assert(setparam->op2 != NULL); /* container_name */ assert(setparam->op3 != NULL); /* target */ assert(s->stack->transfer != NULL); read_operand(s, &src, setparam->op1); if (spec != NULL) { assert(spec->string_value != NULL); eval_foreign_setparam(s->instance, s->stack->transfer, spec->string_value, src, setparam->op2->bytype.data.name, setparam->op3->bytype.data.name, setparam->annotations); inc_pc(s); return; } assert(s->stack->transfer->transfer_data != NULL); container = fetch_target_container(setparam->op2); assert(container != NULL); assert(setparam->op3->kind == OPERAND_REFERENCE); assert(setparam->op3->bytype.data.ref->loc == SEGMENT_TRANSFER); loc = (char *)s->stack->transfer->transfer_data; loc += setparam->op3->bytype.data.ref->offset; switch (setparam->op3->bytype.data.ref->storage) { case STORAGE_VARIABLE: write_mem(s, (void *)loc, src, setparam->op1->type); break; case STORAGE_DRIVER: case STORAGE_SIGNAL: assert(setparam->op1->type == TYPE_POINTER); write_mem(s, (void *)loc, src, TYPE_POINTER); break; } inc_pc(s); } static void eval_getparam(struct fauhdli_process *s, const struct opcode *getparam) { const struct code_container *container; union fauhdli_value dst; char *loc; dst.pointer = NULL; assert(getparam->op1 != NULL); /* transfer element */ assert(getparam->op2 != NULL); /* container_name */ assert(getparam->op3 != NULL); /* target */ assert(s->stack->transfer != NULL); assert(s->stack->transfer->transfer_data != NULL); container = fetch_target_container(getparam->op2); assert(container != NULL); assert(getparam->op1->kind == OPERAND_REFERENCE); assert(getparam->op1->bytype.data.ref->loc == SEGMENT_TRANSFER); loc = (char *)s->stack->transfer->transfer_data; loc += getparam->op1->bytype.data.ref->offset; switch (getparam->op1->bytype.data.ref->storage) { case STORAGE_VARIABLE: read_mem(s, &dst, (void *)loc, getparam->op3->type); write_operand(s, getparam->op3, dst); break; case STORAGE_DRIVER: case STORAGE_SIGNAL: /* must not be a driver/signal! */ assert(0); break; } inc_pc(s); } static void eval_return(struct fauhdli_process *s, const struct opcode *ret) { struct stack_frame *current = s->stack; assert(current != NULL); s->stack = s->stack->parent; s->pc = current->return_address; } static void eval_update(struct fauhdli_process *s, const struct opcode *update) { union fauhdli_value val; union fauhdli_value delay; union fauhdli_value dst; assert(update->op1 != NULL); assert(update->op2 != NULL); assert(update->op3 != NULL); assert(update->op2->type == TYPE_INT); assert(update->op3->type == TYPE_POINTER); read_operand(s, &val, update->op1); read_operand(s, &delay, update->op2); read_operand(s, &dst, update->op3); driver_update((struct driver *)dst.pointer, val, delay.univ_int + s->instance->sim_time, &s->instance->callbacks); inc_pc(s); } static void eval_getsig(struct fauhdli_process *s, const struct opcode *getsig) { union fauhdli_value sig_ptr; union fauhdli_value val; assert(getsig->op1 != NULL); assert(getsig->op1->type == TYPE_POINTER); assert(getsig->op2 != NULL); assert(getsig->op3 == NULL); read_operand(s, &sig_ptr, getsig->op1); signal_read((const struct signal *)sig_ptr.pointer, &val); write_operand(s, getsig->op2, val); inc_pc(s); } static void eval_connect(struct fauhdli_process *s, const struct opcode *connect) { union fauhdli_value drv; union fauhdli_value sig; bool is_foreign; assert(connect->op1 != NULL); assert(connect->op2 != NULL); assert(connect->op3 == NULL); assert(connect->op1->type == TYPE_POINTER); assert(connect->op2->type == TYPE_POINTER); read_operand(s, &drv, connect->op1); read_operand(s, &sig, connect->op2); is_foreign = driver_connect((struct driver *)drv.pointer, (struct signal *)sig.pointer, s->instance); if (is_foreign) { /* remove driver from process drivers set, and sort * it into foreign_drivers set of instance, * since a foreign driver needs to propagate the * value at a different time during the delta cycle */ assert(slset_contains(s->instance->drivers, drv.pointer)); slset_remove( s->instance->drivers, drv.pointer, s->instance->callbacks.free); slset_add( s->instance->foreign_drivers, drv.pointer, s->instance->callbacks.malloc); } inc_pc(s); } static void eval_wakeat(struct fauhdli_process *s, const struct opcode *wakeat) { union fauhdli_value timeout; assert(wakeat->op1 != NULL); assert(wakeat->op2 == NULL); assert(wakeat->op3 == NULL); read_operand(s, &timeout, wakeat->op1); kernel_add_timeout(s, timeout.univ_int); inc_pc(s); } static void eval_wakeon(struct fauhdli_process *s, const struct opcode *wakeon) { union fauhdli_value sig_ptr; assert(wakeon->op1 != NULL); assert(wakeon->op2 == NULL); assert(wakeon->op3 == NULL); read_operand(s, &sig_ptr, wakeon->op1); kernel_add_sensitivity(s, (struct signal *)sig_ptr.pointer); inc_pc(s); } static void eval_offset(struct fauhdli_process *s, const struct opcode *offset) { union fauhdli_value ptr; union fauhdli_value idx; char *result; assert(offset->op1 != NULL); assert(offset->op2 != NULL); assert(offset->op3 != NULL); assert(offset->indexed_type != NULL); assert(offset->indexed_type->elem_count != -1); assert(offset->op1->type == TYPE_POINTER); assert(offset->op2->type == TYPE_INT); assert(offset->op3->type == TYPE_POINTER); read_operand(s, &ptr, offset->op1); read_operand(s, &idx, offset->op2); result = (char *)ptr.pointer; result += offset->indexed_type->elem_count * sizeof(union fauhdli_value) * idx.univ_int; ptr.pointer = (void *)result; write_operand(s, offset->op3, ptr); inc_pc(s); } static void eval_log(struct fauhdli_process *s, const struct opcode *log) { union fauhdli_value severity; union fauhdli_value c; assert(log->op1 != NULL); assert(log->op2 != NULL); assert(log->op3 == NULL); assert(log->op1->type == TYPE_INT); assert(log->op2->type == TYPE_INT); read_operand(s, &severity, log->op1); read_operand(s, &c, log->op2); log_vhdl( &s->instance->callbacks, (unsigned int)severity.univ_int, s->name, (char)c.univ_int); inc_pc(s); } static void eval_abort(struct fauhdli_process *s, const struct opcode *opc) { assert(s->instance->callbacks.quit != NULL); s->instance->callbacks.quit(1); inc_pc(s); } static void eval_get_sim_time(struct fauhdli_process *s, const struct opcode *opc) { union fauhdli_value sim_time; assert(opc->op1 != NULL); assert(opc->op2 == NULL); assert(opc->op3 == NULL); sim_time.univ_int = s->instance->sim_time; write_operand(s, opc->op1, sim_time); inc_pc(s); } /** evaluate one opcode. * @param s current process * @param opcode opcode to evaluate. * @return true, if the process of the opcode should get suspended, false * otherwise. */ static bool evaluate_opcode(struct fauhdli_process *s, const struct opcode *opcode) { if (s->instance->debug) { kernel_debug(s->instance, "Line %d\n", opcode->lineno); } switch (opcode->kind) { case OPCODE_MOV: eval_mov(s, opcode); break; case OPCODE_ADD: eval_add(s, opcode); break; case OPCODE_SUB: eval_sub(s, opcode); break; case OPCODE_IMUL: eval_imul(s, opcode); break; case OPCODE_DIV: eval_div(s, opcode); break; case OPCODE_CALL: eval_call(s, opcode); break; case OPCODE_PROC: eval_proc(s, opcode); break; case OPCODE_RETURN: eval_return(s, opcode); break; case OPCODE_BEGINTRANS: eval_begintrans(s, opcode); break; case OPCODE_ENDTRANS: eval_endtrans(s, opcode); break; case OPCODE_SETPARAM: eval_setparam(s, opcode); break; case OPCODE_GETPARAM: eval_getparam(s, opcode); break; case OPCODE_UPDATE: eval_update(s, opcode); break; case OPCODE_GETSIG: eval_getsig(s, opcode); break; case OPCODE_JMP: eval_jmp(s, opcode); break; case OPCODE_JE: eval_je(s, opcode); break; case OPCODE_JB: eval_jb(s, opcode); break; case OPCODE_JNE: eval_jne(s, opcode); break; case OPCODE_JBE: eval_jbe(s, opcode); break; case OPCODE_AOFFSET: case OPCODE_ROFFSET: /* both can be evaluated the same */ eval_offset(s, opcode); break; case OPCODE_SUSPEND: inc_pc(s); return true; case OPCODE_WAKEAT: eval_wakeat(s, opcode); break; case OPCODE_WAKEON: eval_wakeon(s, opcode); break; case OPCODE_CONNECT: eval_connect(s, opcode); break; case OPCODE_LOG: eval_log(s, opcode); break; case OPCODE_LABEL: /* nothing to do. just increase the pc */ inc_pc(s); break; case OPCODE_ABORT: eval_abort(s, opcode); return true; case OPCODE_GETSIMTIME: eval_get_sim_time(s, opcode); break; } return false; } static void fauhdli_kernel_execute(struct fauhdli_process *s) { const struct opcode *opcode; const struct slist_entry *last_pc = NULL; while (s->pc != NULL) { bool ret; opcode = (const struct opcode*)s->pc->data; assert(opcode != NULL); last_pc = s->pc; ret = evaluate_opcode(s, opcode); if (last_pc == s->pc) { s->instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", __func__, "Endless loop detected.\n"); /* can happen only, if an opcode doesn't change PC */ s->instance->callbacks.log( FAUHDLI_LOG_DEBUG, "fauhdli", __func__, "pc type=%d\n", opcode->kind); assert(0); } if (ret) { break; } } } static struct code_container * fauhdli_kernel_locate_con_r( struct code_container *container, const char *mangled_name, bool traverse ) { struct slist_entry *i; if (container == NULL) { return NULL; } if (container->sub_containers == NULL) { return NULL; } for (i = container->sub_containers->first; i != NULL; i = i->next) { struct code_container * const c = (struct code_container *)i->data; if (strcmp(c->name, mangled_name) == 0) { return c; } if (traverse) { struct code_container *r; r = fauhdli_kernel_locate_con_r(c, mangled_name, true); if (r != NULL) { return r; } } } return NULL; } /** find the subcontainer with name "name" in container. * @param container container to look through for given text segment. * @param name use subcontainer with this name instead of top-container * @param traverse if true, traverses recursively, otherwise just * looks at direct subcontainers. * @return subcontainer, or NULL if not found. */ static struct code_container * fauhdli_kernel_find_con( const struct glue_vhdl_cb *callbacks, struct code_container *container, const char *name, bool traverse ) { struct code_container *c; char buf[2048]; int r; if (name == NULL) { return container; } r = mangle_name(name, buf, sizeof(buf)); if (r == sizeof(buf)) { callbacks->log(FAUHDLI_LOG_ERROR, "fauhdli", "kernel", "Name \"%s\" too long!\n", name); return NULL; } c = fauhdli_kernel_locate_con_r(container, buf, traverse); return c; } /** clear event flag of all signals * @param all_sigs set containing all signals */ static void fauhdli_kernel_clear_event(struct slset *all_sigs) { struct slset_entry *i; for (i = all_sigs->first; i != NULL; i = i->next) { signal_clear_event((struct signal *)i->data); } } static void fauhdli_kernel_drv_propagate( struct fauhdli *instance, struct slset *s, /* FIXME both parts of instance */ universal_integer sim_time ) { struct slset_entry *i; for (i = s->first; i != NULL; i = i->next) { signal_drivers_propagate(instance, (struct signal *)i->data, sim_time); } } static void fauhdli_kernel_process_wake( struct vhdl_sched *sched, struct fauhdli_process *p, universal_integer sim_time ) { struct slset_entry *i; bool wakeup = false; /* if any sensitivity has an event, wakeup the process */ for (i = p->sensitivities->first; i != NULL; i = i->next) { struct signal *s = (struct signal *)i->data; if (s->event) { wakeup = true; break; } } if (p->next_event <= sim_time) { wakeup = true; } if (! wakeup) { return; } /* wakeup/reset process */ slset_clear(p->sensitivities, p->instance->callbacks.free); p->next_event = INT64_MAX; vhdl_sched_wakeup(sched, p, &p->instance->callbacks); } static universal_integer fauhdli_kernel_get_next_time( const struct slset *all_procs, const struct slset *all_drvs, const struct slset *foreign_drivers ) { const struct slset_entry *i; universal_integer ret = INT64_MAX; for (i = all_procs->first; i != NULL; i = i->next) { const struct fauhdli_process *p = (const struct fauhdli_process *)i->data; if (p->next_event < ret) { ret = p->next_event; } } for (i = all_drvs->first; i != NULL; i = i->next) { universal_integer d_event; const struct driver *d = (const struct driver*)i->data; d_event = driver_get_next_event(d); if (d_event < ret) { ret = d_event; } } for (i = foreign_drivers->first; i != NULL; i = i->next) { universal_integer d_event; const struct driver *d = (const struct driver *)i->data; d_event = driver_get_next_event(d); if (d_event < ret) { ret = d_event; } } return ret; } /** propagate all current driving values of foreign (out) drivers */ static void fauhdli_kernel_forward_foreign_drvs( struct fauhdli *instance, universal_integer sim_time ) { struct slset_entry *i; for (i = instance->foreign_drivers->first; i != NULL; i = i->next) { struct driver *drv = (struct driver *)i->data; driver_forward_foreign(instance, drv, sim_time); } } static universal_integer fauhdli_kernel_simulation_start(struct fauhdli *instance) { universal_integer t_next; /* calculate initial values/driving values (done implicitly here) */ /* run all processes */ vhdl_sched_run(instance->scheduler, &instance->callbacks); /* determine t_next */ t_next = fauhdli_kernel_get_next_time(instance->processes, instance->drivers, instance->foreign_drivers); return t_next; } void fauhdli_kernel_simulation_cycle(void *_instance) { struct fauhdli *instance = (struct fauhdli *)_instance; struct slset_entry *i; universal_integer t_next; /* no need to schedule wakeups *during* the delta cycle */ instance->wakeup_scheduled = true; while (true) { /* a: advance time, exit if sim_time == INT64_MAX */ t_next = (int64_t)instance->callbacks.time_virt(); assert(0 <= t_next); instance->sim_time = t_next; if (instance->sim_time == INT64_MAX) { instance->callbacks.log( FAUHDLI_LOG_INFO, "fauhdli", "kernel", "simulation end.\n"); return; } /* b: update explicit signals */ fauhdli_kernel_drv_propagate(instance, instance->signals, instance->sim_time); /* c: update implicit signals (no implicit signals * right now, TODO) */ /* d: wake up all processes with events */ for (i = instance->processes->first; i != NULL; i = i->next) { fauhdli_kernel_process_wake( instance->scheduler, (struct fauhdli_process *)i->data, instance->sim_time); } /* e0: "run foreign process" (aka call foreign signal set * methods on active drivers) */ fauhdli_kernel_forward_foreign_drvs(instance, t_next); /* e1: resume all processes with events */ vhdl_sched_run(instance->scheduler, &instance->callbacks); fauhdli_kernel_clear_event(instance->signals); /* f: next_time = min(driver, processes, time'high), * delta cycle present if next_time == sim_time */ t_next = fauhdli_kernel_get_next_time(instance->processes, instance->drivers, instance->foreign_drivers); if (t_next == instance->sim_time) { continue; } if ((instance->tracer != NULL) && (t_next != INT64_MAX)) { trace_time_advance(instance->tracer, t_next); } #if 0 /* no postponed processes currently */ /* g: if not delta_cycle: execute all postponed processes, * recalculate next_time according to f */ t_next = fauhdli_kernel_get_next_time(instance->processes); #endif /* no delta cycle... return */ instance->callbacks.time_call_at( t_next, fauhdli_kernel_simulation_cycle, instance); instance->wakeup_scheduled = false; return; } } /** start the simulation cycle and schedule the following * The following runs can be executed via fauhdli_kernel_simulation_cycle. * @param _instance fauhdli instance. */ static void fauhdli_kernel_cycle_start(void *_instance) { struct fauhdli *instance = (struct fauhdli *)_instance; universal_integer t_next; assert(instance != NULL); assert(instance->scheduler != NULL); if (! vhdl_sched_has_runnable(instance->scheduler)) { instance->callbacks.log( FAUHDLI_LOG_WARNING, "fauhdli", "kernel", "No process to run.\n"); return; } t_next = fauhdli_kernel_simulation_start(instance); instance->callbacks.time_call_at( t_next, fauhdli_kernel_simulation_cycle, instance); } static const struct fauhdli_process * fauhdli_kernel_find_process(const struct fauhdli *instance, const char *name) { struct slset_entry *i; char buf[2048]; int ret; for (i = instance->processes->first; i != NULL; i = i->next) { const struct fauhdli_process *p = (const struct fauhdli_process *)i->data; char *c; ret = demangle_name(p->name, buf, sizeof(buf)); assert(ret >= 0); assert((size_t)ret < sizeof(buf)); c = strrchr(buf, ':'); assert(c != NULL); *c = '\0'; if (strcmp(name, buf) == 0) { return p; } } return NULL; } static void fauhdli_kernel_trace(struct fauhdli *instance) { struct slist_entry *i; if (instance->tracer == NULL) { return; } for (i = instance->trace_list->first; i != NULL; i = i->next) { const char *s = (const char *)i->data; struct code_container *container; container = fauhdli_kernel_find_con( &instance->callbacks, instance->container, s, true); if (container == NULL) { instance->callbacks.log(FAUHDLI_LOG_WARNING, "fauhdli", "kernel", "Cannot find entity <%s>, skipping " "trace.\n", s); } else { /* FIXME hideous: locate a process in the entity * and go one hierarchy above, that's the stack * segment. */ const struct fauhdli_process *p = fauhdli_kernel_find_process(instance, s); assert(p != NULL); assert(p->stack != NULL); assert(p->stack->static_parent != NULL); fauhdli_trace_segment( instance, container->stack_segment, p->stack->static_parent->data); } } } void fauhdli_kernel_resolve( struct fauhdli *instance, const struct code_container *resolver, union fauhdli_value *ret, union fauhdli_value *drv_values, size_t sz ) { struct fauhdli_process *process; union fauhdli_value *data; process = process_create(&instance->callbacks); process->pc = resolver->text_segment->first; process->instance = instance; /* since the resolution function must be pure, it mustn't * access any values outside of the function itself, hence * there is no need to create a static_parent. */ process->stack = create_stack_frame(process, resolver, NULL, NULL, ""); /* loop the stack frame, "return" opcode will otherwise overwrite it*/ process->stack->parent = process->stack; /* getting ugly: we neither know what the transfer variables are * called, nor do we have these resolved by symbol table. * But we do know how fauhdlc orders them, and that it's exactly * one unconstraint array as parameter to the resolution function. * Hence we can manually fumble things into place here. */ /* the transfer variable order is * array base pointer * array lower bound * array upper bound * array direction * return value. */ data = (union fauhdli_value *)process->stack->transfer_data; /* array base pointer */ data->pointer = drv_values; data++; /* lower bound */ data->univ_int = 0; data++; /* upper bound */ data->univ_int = sz - 1; data++; /* direction (to = 1) */ data->univ_int = 1; data++; /* now pointing to return value */ fauhdli_kernel_execute(process); *ret = *data; fauhdli_kernel_destroy_stack_frame( process->stack, &instance->callbacks); process_destroy(process); } void fauhdli_kernel_destroy(struct fauhdli *instance) { struct slset_entry *i; for (i = instance->pending_stack_frames->first; i != NULL; i = i->next) { fauhdli_kernel_destroy_stack_frame( (struct stack_frame *)i->data, &instance->callbacks); } for (i = instance->processes->first; i != NULL; i = i->next) { process_destroy((struct fauhdli_process *)i->data); } for (i = instance->drivers->first; i != NULL; i = i->next) { struct driver *drv = (struct driver *)i->data; driver_destroy(drv, &instance->callbacks); } for (i = instance->foreign_drivers->first; i != NULL; i = i->next) { struct driver *drv = (struct driver *)i->data; driver_destroy(drv, &instance->callbacks); } } void fauhdli_kernel_init(struct fauhdli *instance, const char *top_entity) { struct fauhdli_process *process; struct code_container *container; const char *n; assert(instance->container != NULL); process = process_create(&instance->callbacks); if (instance->container->transfer_segment != NULL) { instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", "kernel", "Top container needs parameters.\n"); return; } container = fauhdli_kernel_find_con( &instance->callbacks, instance->container, top_entity, false); if (container == NULL) { instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", "kernel", "cannot locate container %s as child of top " "container.\n", top_entity); return; } if (container->text_segment == NULL) { instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", "kernel", "No code to run in container. Exiting.\n"); return; } if (container->transfer_segment != NULL) { if (top_entity == NULL) { n = "top"; } else { n = top_entity; } instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", "kernel", "Container %s needs parameters\n", n); return; } process->pc = container->text_segment->first; process->instance = instance; process->stack = create_stack_frame(process, instance->container, NULL, NULL, ""); if (container != instance->container) { /* must be a direct child of container */ process->stack->transfer = create_stack_frame( process, container, process->stack, process->stack, ""); process->stack = process->stack->transfer; } fauhdli_kernel_execute(process); if (process->stack != NULL) { slset_add( instance->pending_stack_frames, process->stack, instance->callbacks.malloc); if (process->stack->transfer != NULL) { slset_add( instance->pending_stack_frames, process->stack->transfer, instance->callbacks.malloc); } } process_destroy(process); /* make sure, tracer is initialised *after* setup process was run */ fauhdli_kernel_trace(instance); instance->callbacks.time_call_at( 0, fauhdli_kernel_cycle_start, instance); } fauhdlc-20130704/interpreter/signals.c0000664000175000017500000002252711726230621017161 0ustar potyrapotyra/* $Id: signals.c 5110 2012-03-08 22:24:17Z potyra $ * * Signal/Driver handling related functions. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "signals.h" #include #include #include #include "glue-main.h" /* for time_virt */ #include "glue-log.h" #include "kernel.h" /** transaction element of a driver */ struct drv_trans { /** simulation time at which the transaction is to happen */ universal_integer sim_time; /** value of the driver at given time. */ union fauhdli_value val; }; /** ordering function for transactions of a driver in ascending simulation * time order. */ static int __attribute__((__pure__)) drv_trans_compare(const void *_t1, const void *_t2) { const struct drv_trans *t1 = (const struct drv_trans *)_t1; const struct drv_trans *t2 = (const struct drv_trans *)_t2; if (t1->sim_time < t2->sim_time) { return -1; } if (t1->sim_time == t2->sim_time) { return 0; } return 1; } static void driver_connect_non_foreign( struct driver *driver, struct signal *_signal, const struct glue_vhdl_cb *callbacks ) { assert(driver != NULL); assert(_signal != NULL); slset_add(_signal->connected_drivers, driver, callbacks->malloc); driver->connected_signal = _signal; } bool driver_connect( struct driver *driver, struct signal *_signal, struct fauhdli *instance ) { if (_signal->is_foreign) { /* foreign out drivers are NOT connected * to the VHDL signal! these directly forward * the value to the foreign signal via glue_vhdl */ assert(instance->callbacks.connect_out != NULL); instance->callbacks.connect_out( instance->glue_vhdl, _signal->foreign_id, _signal->value, driver); driver->foreign_out = true; driver->foreign_id = _signal->foreign_id; return true; } driver_connect_non_foreign(driver, _signal, &instance->callbacks); return false; } static void driver_disconnect(struct driver *driver, const struct glue_vhdl_cb *callbacks) { if (driver->connected_signal == NULL) { /* not connected */ return; } assert(driver->connected_signal->connected_drivers != NULL); slset_remove( driver->connected_signal->connected_drivers, driver, callbacks->free); driver->connected_signal = NULL; } struct driver * driver_create(union fauhdli_value init, const struct glue_vhdl_cb *callbacks) { struct driver *ret; ret = callbacks->malloc(sizeof(struct driver)); assert(ret != NULL); ret->driving_value = init; ret->connected_signal = NULL; ret->active = false; ret->transactions = slset_create(drv_trans_compare, callbacks->malloc); ret->foreign_out = false; ret->foreign_id = 0; return ret; } void driver_destroy(struct driver *driver, const struct glue_vhdl_cb *callbacks) { driver_disconnect(driver, callbacks); slset_destroy_data(driver->transactions, callbacks->free); callbacks->free(driver); } void driver_update( struct driver *driver, union fauhdli_value val, universal_integer sim_time, const struct glue_vhdl_cb *callbacks ) { struct drv_trans *t; t = callbacks->malloc(sizeof(struct drv_trans)); assert(t != NULL); t->sim_time = sim_time; t->val = val; slset_truncate_at(driver->transactions, t, true, callbacks->free); slset_add(driver->transactions, t, callbacks->malloc); } /** Update driving_value from the transactions at a given simulation * time. * @param driver driver to look up current transaction * @param sim_time current simulation time. * @return true, if the driver is now active, false if not * (FIXME: actually active should be set correctly instead!) */ static bool update_driving_value( struct driver *driver, universal_integer sim_time, const struct glue_vhdl_cb *callbacks ) { struct drv_trans *t; if (driver->transactions->first == NULL) { return false; } t = (struct drv_trans *)driver->transactions->first->data; if (sim_time < t->sim_time) { /* entry in the future */ return false; } /* entry now or in the past (FAUmachine's CPU isn't keeping * exact track of the time, so registered event callbacks may * come at a later point in simulation time than these * have been scheduled -- however only if the schedule updated * *while* the CPU is running. */ driver->active = true; driver->driving_value = t->val; slset_remove(driver->transactions, t, callbacks->free); callbacks->free(t); return true; } static void driver_propagate( struct driver *driver, universal_integer sim_time, const struct glue_vhdl_cb *callbacks ) { bool active; /* FIXME reset active somewhere */ active = update_driving_value(driver, sim_time, callbacks); if (! active) { return; } if (memcmp(&driver->connected_signal->value, &driver->driving_value, sizeof(union fauhdli_value)) != 0) { driver->connected_signal->event = true; driver->connected_signal->value = driver->driving_value; } assert(! driver->foreign_out); } void driver_forward_foreign( struct fauhdli *instance, struct driver *driver, universal_integer sim_time ) { bool active; assert(driver->foreign_out); active = update_driving_value( driver, sim_time, &instance->callbacks); if (! active) { return; } assert(driver->connected_signal == NULL); assert(instance->callbacks.drv_set != NULL); instance->callbacks.drv_set(instance->glue_vhdl, driver->foreign_id, driver->driving_value, driver); } static void signal_drivers_propagate_unresolved( const struct glue_vhdl_cb *callbacks, struct signal *sig, universal_integer sim_time ) { static bool error_reported = false; unsigned int n_drivers = 0; struct slset_entry *i; for (i = sig->connected_drivers->first; i != NULL; i = i->next) { struct driver *d = (struct driver *)i->data; assert(! d->foreign_out); driver_propagate(d, sim_time, callbacks); n_drivers++; } if ((1 < n_drivers) && (! error_reported)) { error_reported = true; callbacks->log(FAUHDLI_LOG_CRITICAL, "fauhdli", __func__, "There is more than one driver for an unresoved " "signal.\n"); } } void signal_drivers_propagate( struct fauhdli *instance, struct signal *sig, universal_integer sim_time ) { struct slset_entry *i; union fauhdli_value drv_args[10]; union fauhdli_value ret; size_t num_drvs = 0; bool active = false; if (sig->resolver == NULL) { signal_drivers_propagate_unresolved( &instance->callbacks, sig, sim_time); } /* resolved signal */ /* collect driving values */ for (i = sig->connected_drivers->first; i != NULL; i = i->next) { struct driver *d = (struct driver *)i->data; assert(! d->foreign_out); active |= update_driving_value(d, sim_time, &instance->callbacks); assert(num_drvs < (sizeof(drv_args) / sizeof(drv_args[0]))); drv_args[num_drvs] = d->driving_value; num_drvs++; } /* FIXME does that adhere to lrm? */ if (! active) { return; } /* let the kernel call the resolution function */ fauhdli_kernel_resolve(instance, sig->resolver, &ret, drv_args, num_drvs); if (memcmp(&sig->value, &ret, sizeof(union fauhdli_value)) != 0) { sig->event = true; sig->value = ret; } } universal_integer driver_get_next_event(const struct driver *drv) { const struct slset_entry *i; const struct drv_trans *t; if (slset_empty(drv->transactions)) { return INT64_MAX; } i = drv->transactions->first; t = (const struct drv_trans *)i->data; return t->sim_time; } struct signal * signal_create( union fauhdli_value init, const char *foreign, struct fauhdli *instance, const char *name, const struct code_container *resolver ) { struct signal *ret; ret = instance->callbacks.malloc(sizeof(struct signal)); assert(ret != NULL); ret->value = init; ret->connected_drivers = slset_create(NULL, instance->callbacks.malloc); ret->event = false; ret->resolver = resolver; if (foreign == NULL) { ret->is_foreign = false; ret->foreign_id = 0; return ret; } /* foreign signal */ ret->is_foreign = true; assert(instance->callbacks.signal_create != NULL); ret->foreign_id = instance->callbacks.signal_create( instance->glue_vhdl, foreign, name); return ret; } void signal_destroy(struct signal *_signal, const struct glue_vhdl_cb *callbacks) { if (_signal->connected_drivers != NULL) { slset_destroy(_signal->connected_drivers, callbacks->free); } callbacks->free(_signal); } void signal_connect_foreign_in_driver( struct signal *sig, struct fauhdli *instance, struct slset *driver_set ) { struct driver *drv; union fauhdli_value init; /* FIXME obtain foreign value */ init.univ_int = 0; drv = driver_create(init, &instance->callbacks); driver_connect_non_foreign(drv, sig, &instance->callbacks); sig->value = init; assert(instance->callbacks.connect_in != NULL); instance->callbacks.connect_in( instance->glue_vhdl, sig->foreign_id, drv); slset_add(driver_set, drv, instance->callbacks.malloc); } unsigned int fauhdli_get_sig_id(const void *_sig) { const struct signal *sig = (const struct signal*)_sig; assert(sig != NULL); assert(sig->is_foreign); return sig->foreign_id; } unsigned int fauhdli_get_sig_id_driver(const void *_drv) { const struct driver *drv = (const struct driver *)_drv; assert(drv != NULL); assert(drv->foreign_out == true); return drv->foreign_id; } fauhdlc-20130704/interpreter/icscanner.l0000664000175000017500000001166511717541301017500 0ustar potyrapotyra/* $Id: icscanner.l 5107 2012-02-17 21:12:33Z potyra $ * vim:tabstop=8 shiftwidth=8 textwidth=72: * Scanner for intermediate code. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ /* options */ %option case-insensitive %option noyywrap %option nounput %option yylineno %option noinput /* start conditions */ /* tokens found in annotations, most will be thrown away */ %x ANNOTATION /* any specification in the form name=int | name="string" found in * annotations */ %x ANNOTATION_SPEC %{ #include #include #include "fauhdli_private.h" #include "icparser.h" #include "glue-log.h" #include "fauhdlstring.h" #define YY_DECL \ int yylex(\ const struct fauhdli *instance, \ const char *filename\ ) %} char [a-zA-Z] id_char [_a-zA-Z0-9] digit [0-9] pos_number {digit}{digit}* number -?{pos_number} fraction \.{pos_number} integer \${number}L real \${number}{fraction}?F identifier {id_char}*{char}{id_char}* ref_str {id_char}* reference \"{ref_str}\" label {identifier}: target @{identifier} ws_char [ \t] whitespace {ws_char}* register %reg_{pos_number} type_spec_i i type_spec_f f type_spec_p p a_name {identifier} a_string {reference} a_int [0-9]+ a_spec_int {a_name}={a_int} a_spec_string {a_name}={a_string} a_spec {a_spec_int}|{a_spec_string} %% <*>"\n" { yylloc.first_line++; } <*>{whitespace} {} "}" { BEGIN(INITIAL); } {a_spec} { BEGIN(ANNOTATION_SPEC); yyless(0); } "=" { return t_AnnotateEqSym; } {a_name} { yylval.text = fauhdlstrdup(yytext, instance->callbacks.malloc); return t_AnnotateName; } {a_string} { yylval.text = fauhdlstrdup(&yytext[1], instance->callbacks.malloc); yylval.text[strlen(yylval.text) - 1] = '\0'; BEGIN(ANNOTATION); return t_AnnotateString; } {a_int} { yylval.annotate_int = atoi(yytext); BEGIN(ANNOTATION); return t_AnnotateInt; } . { /* anything unmatched is ok in annotations as well, and won't result in a token */ } "(" { return t_LeftParen; } ")" { return t_RightParen; } "[" { return t_LeftBracket; } "]" { return t_RightBracket; } "," { return t_Comma; } ":" { return t_Colon; } ":=" { return t_ValAssign; } "->" { return t_Arrow; } ; { return t_Semicolon; } ".registers" { return t_Registers; } ".text" { return t_CodeSegment; } ".stack" { return t_StackSegment; } ".transfer" { return t_TransferSegment; } ".types" { return t_TypeSegment; } "{" { BEGIN(ANNOTATION); } is { return t_IS; } mov { return t_MOV; } abort { return t_ABORT; } add { return t_ADD; } sub { return t_SUB; } imul { return t_IMUL; } div { return t_DIV; } call { return t_CALL; } return { return t_RETURN; } proc { return t_PROC; } update { return t_UPDATE; } getsig { return t_GETSIG; } gettime { return t_GETSIMTIME; } jmp { return t_JMP; } je { return t_JE; } jb { return t_JB; } jbe { return t_JBE; } jne { return t_JNE; } aoffset { return t_AOFFSET; } roffset { return t_ROFFSET; } data { return t_DATA; } type { return t_TYPE; } container { return t_CONTAINER; } signal { return t_SIGNAL; } driver { return t_DRIVER; } variable { return t_VARIABLE; } connect { return t_CONNECT; } end { return t_END; } begintr { return t_BEGINTRANSFER; } endtr { return t_ENDTRANSFER; } getparm { return t_GETPARAM; } setparm { return t_SETPARAM; } resolvedby { return t_RESOLVEDBY; } suspend { return t_SUSPEND; } wakeon { return t_WAKEON; } wakeat { return t_WAKEAT; } log { return t_LOG; } {type_spec_i} { return t_TypeSpecInt; } {type_spec_f} { return t_TypeSpecFloat; } {type_spec_p} { return t_TypeSpecPointer; } {register} { yylval.number = atol(&yytext[5]); return t_Register; } {label} { yylval.text = fauhdlstrdup(yytext, instance->callbacks.malloc); /* drop trailing ":" */ yylval.text[strlen(yylval.text) - 1] = '\0'; return t_Label; } {identifier} { yylval.text = fauhdlstrdup(yytext, instance->callbacks.malloc); return t_Identifier; } {reference} { /* remove quotes */ yylval.text = fauhdlstrdup(&yytext[1], instance->callbacks.malloc); yylval.text[strlen(yylval.text) - 1] = '\0'; return t_Reference; } {integer} { yylval.univ_int = atoll(&yytext[1]); return t_Int; } {real} { yylval.univ_real = atof(&yytext[1]); return t_Float; } {pos_number} { yylval.univ_int = atoll(yytext); return t_PosNumber; } {target} { yylval.text = fauhdlstrdup(&yytext[1], instance->callbacks.malloc); return t_Target; } . { instance->callbacks.log( FAUHDLI_LOG_ERROR, "fauhdli", "scanner", "%s:%d: invalid character '%c' in stream.\n", filename, yylineno, yytext[0]); return t_Invalid; } fauhdlc-20130704/interpreter/signals.h0000664000175000017500000001272211261365331017163 0ustar potyrapotyra/* $Id: signals.h 4795 2009-10-02 11:58:17Z potyra $ * * Signal/Driver handling related functions. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SIGNALS_H_INCLUDED #define __SIGNALS_H_INCLUDED #include "fauhdli_private.h" #include /** a VHDL signal */ struct signal { /** current signal value */ union fauhdli_value value; /** set of drivers, that are connected to the signal */ struct slset *connected_drivers; /** signal value was changed in the delta cycle. */ bool event; /** is this a "foreign" signal? */ bool is_foreign; /** id of the foreign signal */ unsigned int foreign_id; /** associated resolution function (if any) */ const struct code_container *resolver; }; /** a VHDL driver */ struct driver { /** current driving value of the driver */ union fauhdli_value driving_value; /** signal to which the driver is connected to (or NULL) */ struct signal *connected_signal; /** is the driver active during this delta cycle? (i.e. it * recieved any update) * FIXME not set correctly! */ bool active; /** transactions on the driver */ struct slset *transactions; /** is this a foreign out driver? */ bool foreign_out; /** id of the foreign signal (if any) */ unsigned int foreign_id; }; /** connect a driver to a signal * @param driver driver that should get connected to signal * @param signal signal that the driver should get connected to. * @param instance fauhdli instance. * @return true if it is a foreign driver, false otherwise. */ extern bool driver_connect( struct driver *driver, struct signal *_signal, struct fauhdli *instance ); /** create a driver at *driver_p. * @param init initial value of the driver. * @param callbacks callbacks (for malloc) * @return created driver instance. */ extern struct driver * driver_create(union fauhdli_value init, const struct glue_vhdl_cb *callbacks); /** destroy a driver (freeing the memory). * @param driver driver to destroy * @param callbacks for free. */ extern void driver_destroy(struct driver *driver, const struct glue_vhdl_cb *callbacks); /** update a driver with a new value after a specific delay. * @param driver driver instance. * @param val new driving value. * @param sim_time simulation time at which the update should be * performed. * @param callbacks callbacks for malloc. */ extern void driver_update( struct driver *driver, union fauhdli_value val, universal_integer sim_time, const struct glue_vhdl_cb *callbacks ); /** propagate the driving value to the (foreign) signal via * glue-vhdl. * @param instance fauhdli instance. * @param driver driver to propagate the value to the signal * @param sim_time current simulation time. */ extern void driver_forward_foreign( struct fauhdli *instance, struct driver *driver, universal_integer sim_time ); /** propagate all driving values of the drivers to the signal. * foreign_out drivers will not get propagated. * * @param instance fauhdli instance * @param sig signal which should get updated. * @param sim_time current simulation time. */ extern void signal_drivers_propagate( struct fauhdli *instance, struct signal *sig, universal_integer sim_time ); /** determine the time of the next event on a driver. * @param drv driver instance. * @return scheduled simulation time of next event, or INT64_MAX in case * no event is scheduled. */ extern universal_integer driver_get_next_event(const struct driver *drv); /** create a VHDL signal. If foreign is specified, a foreign signal will * additionally get created. * @param init initial value of the signal. * @param foreign name of foreign signal to create, or NULL if not foreign. * @param instance fauhdli instance. * @param name name for debugging only * @param resolver resolution function container (or NULL if unresolved) * @return pointer to newly created signal. */ extern struct signal * signal_create( union fauhdli_value init, const char *foreign, struct fauhdli *instance, const char *name, const struct code_container *resolver ); /** destroy a signal. This won't destroy the associated drivers. * @param signal signal to destroy * @param callbacks for free */ extern void signal_destroy(struct signal *_signal, const struct glue_vhdl_cb *callbacks); /** read the current value of a signal. * @param signal read the signal value from this signal instance. * @param val read value will be stored there. */ static inline void __attribute__((__always_inline__)) signal_read( const struct signal *sig, union fauhdli_value *val ) { *val = sig->value; } /** clear the event flag of the signal * @param sig signal to clear the event flag */ static inline void __attribute__((__always_inline__)) signal_clear_event(struct signal *sig) { sig->event = false; } /* If a foreign signal is read, create a driver for it, add the callback * to glue_vhdl, and set the initial value. * Will do nothing, if not a foreign signal, or the foreign driver is * already created. * * @param sig signal instance. * @param glue_vhdl glue_vhdl instance * @param driver_set add the driver to driver_set. */ extern void signal_connect_foreign_in_driver( struct signal *sig, struct fauhdli *instance, struct slset *driver_set ); #endif /* __SIGNALS_H_INCLUDED */ fauhdlc-20130704/interpreter/icparser.y0000664000175000017500000004410012152355575017360 0ustar potyrapotyra/* $Id: icparser.y 5118 2013-06-01 11:31:09Z potyra $ * * Intermediate code interpreter. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ %error-verbose %defines %parse-param {struct fauhdli *instance} %parse-param {const char *filename} %lex-param {instance} %lex-param {filename} %{ #include "basetypes.h" #include #include #include "fauhdli_private.h" #include "list.h" %} %token t_ABORT %token t_ADD %token t_AOFFSET %token t_BEGINTRANSFER %token t_CALL %token t_CONNECT %token t_CONTAINER %token t_DATA %token t_DIV %token t_DRIVER %token t_END %token t_ENDTRANSFER %token t_GETPARAM %token t_GETSIG %token t_GETSIMTIME %token t_IMUL %token t_IS %token t_JB %token t_JBE %token t_JE %token t_JMP %token t_JNE %token t_LOG %token t_MOV %token t_PROC %token t_RESOLVEDBY %token t_RETURN %token t_ROFFSET %token t_SETPARAM %token t_SIGNAL %token t_SUB %token t_SUSPEND %token t_TYPE %token t_UPDATE %token t_VARIABLE %token t_WAKEAT %token t_WAKEON %token t_Reference %token t_Int %token t_Float %token t_Label %token t_Semicolon %token t_Comma %token t_CodeSegment %token t_StackSegment %token t_TransferSegment %token t_TypeSegment %token t_LeftParen %token t_RightParen %token t_LeftBracket %token t_RightBracket %token t_ValAssign %token t_Target %token t_TypeSpecFloat %token t_TypeSpecInt %token t_TypeSpecPointer %token t_Register %token t_Registers %token t_Identifier %token t_Colon %token t_Arrow %token t_PosNumber %token t_Invalid %token t_AnnotateEqSym %token t_AnnotateName %token t_AnnotateString %token t_AnnotateInt %union { universal_real univ_real; universal_integer univ_int; char * text; unsigned int number; struct operand * operand; struct opcode * opcode; enum storage_kind storage_kind; enum type_kind type_spec; enum opcode_kind opcode_kind; struct slist * list; struct code_container * container; struct data_definition *data_definition; struct type_declaration *type_declaration; struct type_element * type_element; int annotate_int; struct annotation_spec *annotation_spec; }; %{ #include #include #include "glue-log.h" static void yyerror(struct fauhdli *instance, const char *filename, const char *msg); extern int yylex(const struct fauhdli *instance, const char *filename); extern int yylineno; %} /* ---------------- terminals -------------- */ %type t_AnnotateInt %type t_Register %type t_AnnotateName t_AnnotateString t_Identifier t_Label t_Reference t_Target %type type_spec %type t_Int t_PosNumber %type t_Float /* -------------- non-terminals ------------ */ %type annotation_spec annotation_spec_int annotation_spec_string %type container %type data_definition %type annotation_spec_list container_list data_declaration_list list_of_commands immediate_operand_list opt_annotation opt_container_list opt_default_val opt_stack_segment opt_text_segment opt_transfer_segment opt_type_segment stack_segment text_segment transfer_segment type_declaration_list type_list type_segment %type arith_operation cmd_abort cmd_aoffset cmd_begintrans cmd_call cmd_connect cmd_endtrans cmd_getparam cmd_getsig cmd_getsimtime cmd_jmp cmd_log cmd_mov cmd_proc cmd_return cmd_roffset cmd_setparam cmd_suspend cmd_update cmd_wakeat cmd_wakeon command command_wo_annotation conditional_jump label %type arith_opcode cond_jump_opcode %type bool_flag container_name destination immediate_float immediate_int immediate_operand index indirect_operand operand reference_operand register_operand source target transfer_element %type data_kind %type name opt_resolution %type type_declaration %type type type_name %type opt_array %% %start top_container; top_container: container { instance->container = $1; } ; opt_container_list: /* nothing */ { $$ = NULL; } | container_list { $$ = $1; } ; container_list: container_list container { $$ = $1; slist_add($$, $2, instance->callbacks.malloc); } | container { $$ = slist_create(instance->callbacks.malloc); slist_add($$, $1, instance->callbacks.malloc); } ; container: t_CONTAINER name t_Registers t_PosNumber opt_type_segment opt_transfer_segment opt_stack_segment opt_container_list opt_text_segment t_END t_CONTAINER name t_Semicolon { $$ = instance->callbacks.malloc( sizeof(struct code_container)); assert($$ != NULL); $$->name = $2; $$->num_vregs = $4; $$->type_definitions = $5; $$->transfer_segment = $6; $$->stack_segment = $7; $$->sub_containers = $8; $$->text_segment = $9; $$->stack_size = 0; $$->transfer_size = 0; assert($12 != NULL); if (strcmp($2, $12) != 0) { yyerror(instance, filename, "End Container name doesn't match " "container name\n"); instance->callbacks.free($12); YYERROR; } instance->callbacks.free($12); } ; opt_transfer_segment: /* nothing */ { $$ = NULL; } | transfer_segment { $$ = $1; } ; opt_text_segment: /* nothing */ { $$ = NULL; } | text_segment { $$ = $1; } ; opt_stack_segment: /* nothing */ { $$ = NULL; } | stack_segment { $$ = $1; } ; opt_type_segment: /* nothing */ { $$ = NULL; } | type_segment { $$ = $1; } ; transfer_segment: t_TransferSegment data_declaration_list { $$ = $2; } ; text_segment: t_CodeSegment list_of_commands { $$ = $2; } ; stack_segment: t_StackSegment data_declaration_list { $$ = $2; } ; type_segment: t_TypeSegment type_declaration_list { $$ = $2; } ; list_of_commands: list_of_commands command { $$ = $1; slist_add($$, $2, instance->callbacks.malloc); } | command { $$ = slist_create(instance->callbacks.malloc); slist_add($$, $1, instance->callbacks.malloc); } ; data_declaration_list: data_declaration_list data_definition { $$ = $1; slist_add($$, $2, instance->callbacks.malloc); } | data_definition { $$ = slist_create(instance->callbacks.malloc); slist_add($$, $1, instance->callbacks.malloc); } ; type_declaration_list: type_declaration_list type_declaration { $$ = $1; slist_add($$, $2, instance->callbacks.malloc); } | type_declaration { $$ = slist_create(instance->callbacks.malloc); slist_add($$, $1, instance->callbacks.malloc); } ; /* *************** opcodes ************** */ command: command_wo_annotation opt_annotation { $$ = $1; $$->annotations = $2; } command_wo_annotation: cmd_abort { $$ = $1; } | cmd_aoffset { $$ = $1; } | cmd_begintrans { $$ = $1; } | cmd_connect { $$ = $1; } | cmd_call { $$ = $1; } | cmd_endtrans { $$ = $1; } | cmd_getparam { $$ = $1; } | cmd_getsig { $$ = $1; } | cmd_getsimtime { $$ = $1; } | cmd_jmp { $$ = $1; } | cmd_log { $$ = $1; } | cmd_mov { $$ = $1; } | cmd_proc { $$ = $1; } | cmd_return { $$ = $1; } | cmd_roffset { $$ = $1; } | cmd_setparam { $$ = $1; } | cmd_suspend { $$ = $1; } | cmd_wakeat { $$ = $1; } | cmd_wakeon { $$ = $1; } | cmd_update { $$ = $1; } | label { $$ = $1; } | conditional_jump { $$ = $1; } | arith_operation { $$ = $1; } ; label: t_Label { $$ = fauhdli_alloc_opcode(OPCODE_LABEL, &instance->callbacks); $$->label = $1; $$->lineno = @1.first_line; } ; cmd_abort: t_ABORT { $$ = fauhdli_alloc_opcode(OPCODE_ABORT, &instance->callbacks); $$->lineno = @1.first_line; } ; cmd_mov: t_MOV source t_Comma destination { $$ = fauhdli_alloc_opcode(OPCODE_MOV, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->lineno = @1.first_line; if ($2->type != $4->type) { yyerror(instance, filename, "operands must be of same type for MOV."); YYERROR; } } ; /* TODO 3rd operand is reserved so far */ cmd_getsig: t_GETSIG source t_Comma destination { /* source is signal, destination the result of the signal */ $$ = fauhdli_alloc_opcode(OPCODE_GETSIG, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->lineno = @1.first_line; } ; cmd_getsimtime: t_GETSIMTIME destination { $$ = fauhdli_alloc_opcode(OPCODE_GETSIMTIME, &instance->callbacks); $$->op1 = $2; $$->lineno = @1.first_line; } ; cmd_jmp: t_JMP target { $$ = fauhdli_alloc_opcode(OPCODE_JMP, &instance->callbacks); $$->op1 = $2; $$->lineno = @1.first_line; } ; cmd_aoffset: t_AOFFSET source t_Comma type_name index t_Comma destination { $$ = fauhdli_alloc_opcode(OPCODE_AOFFSET, &instance->callbacks); $$->op1 = $2; $$->op2 = $5; $$->op3 = $7; $$->indexed_type = $4; $$->lineno = @1.first_line; } ; cmd_roffset: t_ROFFSET source t_Comma type_name t_Arrow t_Int t_Comma destination { $$ = fauhdli_alloc_opcode(OPCODE_ROFFSET, &instance->callbacks); $$->op1 = $2; $$->op2 = instance->callbacks.malloc(sizeof(struct operand)); assert($$->op2 != NULL); $$->op2->kind = OPERAND_IMMEDIATE; $$->op2->type = TYPE_INT; $$->op2->bytype.immediate.univ_int = $6; $$->op3 = $8; $$->indexed_type = $4; $$->lineno = @1.first_line; } ; cmd_call: t_CALL container_name { $$ = fauhdli_alloc_opcode(OPCODE_CALL, &instance->callbacks); $$->op1 = $2; $$->lineno = @1.first_line; } ; cmd_proc: t_PROC container_name { $$ = fauhdli_alloc_opcode(OPCODE_PROC, &instance->callbacks); $$->op1 = $2; $$->lineno = @1.first_line; } ; cmd_return: t_RETURN { $$ = fauhdli_alloc_opcode(OPCODE_RETURN, &instance->callbacks); $$->lineno = @1.first_line; } ; cmd_update: t_UPDATE source t_Comma operand t_Comma destination { $$ = fauhdli_alloc_opcode(OPCODE_UPDATE, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->op3 = $6; $$->lineno = @1.first_line; } ; cmd_suspend: t_SUSPEND { $$ = fauhdli_alloc_opcode(OPCODE_SUSPEND, &instance->callbacks); $$->lineno = @1.first_line; } ; cmd_wakeat: t_WAKEAT source { $$ = fauhdli_alloc_opcode(OPCODE_WAKEAT, &instance->callbacks); $$->op1 = $2; $$->lineno = @1.first_line; } ; cmd_wakeon: t_WAKEON source { $$ = fauhdli_alloc_opcode(OPCODE_WAKEON, &instance->callbacks); $$->op1 = $2; $$->lineno = @1.first_line; } ; cmd_begintrans: t_BEGINTRANSFER container_name t_Comma container_name { $$ = fauhdli_alloc_opcode(OPCODE_BEGINTRANS, &instance->callbacks); $$->op1 = $2; $$->lineno = @1.first_line; $$->op2 = $4; } ; cmd_endtrans: t_ENDTRANSFER container_name t_Comma bool_flag { $$ = fauhdli_alloc_opcode(OPCODE_ENDTRANS, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->lineno = @1.first_line; } ; cmd_setparam: t_SETPARAM source t_Comma container_name t_Comma transfer_element { $$ = fauhdli_alloc_opcode(OPCODE_SETPARAM, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->op3 = $6; $$->lineno = @1.first_line; } ; cmd_getparam: t_GETPARAM transfer_element t_Comma container_name t_Comma destination { $$ = fauhdli_alloc_opcode(OPCODE_GETPARAM, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->op3 = $6; $$->lineno = @1.first_line; } ; cmd_connect: t_CONNECT source t_Comma destination { $$ = fauhdli_alloc_opcode(OPCODE_CONNECT, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->lineno = @1.first_line; } ; cmd_log: t_LOG operand t_Comma operand { $$ = fauhdli_alloc_opcode(OPCODE_LOG, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->lineno = @1.first_line; } ; cond_jump_opcode: t_JB { $$ = OPCODE_JB; } | t_JBE { $$ = OPCODE_JBE; } | t_JE { $$ = OPCODE_JE; } | t_JNE { $$ = OPCODE_JNE; } ; conditional_jump: cond_jump_opcode source t_Comma operand t_Comma target { $$ = fauhdli_alloc_opcode($1, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->op3 = $6; $$->lineno = @1.first_line; if ($2->type != $4->type) { yyerror(instance, filename, "Compare operands must be of same type for " "conditional branch."); YYERROR; } } ; arith_opcode: t_ADD { $$ = OPCODE_ADD; } | t_SUB { $$ = OPCODE_SUB; } | t_IMUL { $$ = OPCODE_IMUL; } | t_DIV { $$ = OPCODE_DIV; } ; arith_operation: arith_opcode source t_Comma operand t_Comma destination { $$ = fauhdli_alloc_opcode($1, &instance->callbacks); $$->op1 = $2; $$->op2 = $4; $$->op3 = $6; $$->lineno = @1.first_line; if (($2->type != $4->type) || ($2->type != $6->type)) { yyerror(instance, filename, "Operands must be of same type for " "arithmetic opcode."); YYERROR; } } ; /* ************** operands ************** */ container_name: reference_operand { $$ = $1; } ; transfer_element: reference_operand { $$ = $1; } ; target: t_Target { $$ = instance->callbacks.malloc(sizeof(struct operand)); assert($$ != NULL); $$->kind = OPERAND_TARGET; $$->type = TYPE_POINTER; $$->bytype.target.name = $1; $$->bytype.target.ref = NULL; } ; source: operand { $$ = $1; } ; destination: operand { $$ = $1; } ; operand: immediate_operand { $$ = $1; } | register_operand { $$ = $1; } | indirect_operand { $$ = $1; } | reference_operand { $$ = $1; } ; bool_flag: immediate_int { $$ = $1; } ; immediate_operand: immediate_int { $$ = $1; } | immediate_float { $$ = $1; } ; immediate_int: t_Int { $$ = instance->callbacks.malloc(sizeof(struct operand)); assert($$ != NULL); $$->kind = OPERAND_IMMEDIATE; $$->type = TYPE_INT; $$->bytype.immediate.univ_int = $1; } ; immediate_float: t_Float { $$ = instance->callbacks.malloc(sizeof(struct operand)); assert($$ != NULL); $$->kind = OPERAND_IMMEDIATE; $$->type = TYPE_FLOAT; $$->bytype.immediate.univ_real = $1; } ; reference_operand: t_Reference { $$ = instance->callbacks.malloc(sizeof(struct operand)); assert($$ != NULL); $$->kind = OPERAND_REFERENCE; $$->type = TYPE_POINTER; $$->bytype.data.name = $1; $$->bytype.data.ref = NULL; } ; indirect_operand: type_spec t_LeftParen register_operand t_RightParen { if ($3->type != TYPE_POINTER) { yyerror(instance, filename, "Indirect addressing but register " "is no pointer."); YYERROR; } $$ = $3; $3->kind = OPERAND_INDIRECT; $$->type = $1; } ; register_operand: type_spec t_Register { $$ = instance->callbacks.malloc(sizeof(struct operand)); assert($$ != NULL); $$->kind = OPERAND_REGISTER; $$->type = $1; $$->bytype.reg = $2; } ; type_spec: t_TypeSpecInt { $$ = TYPE_INT; } | t_TypeSpecFloat { $$ = TYPE_FLOAT; } | t_TypeSpecPointer { $$ = TYPE_POINTER; } ; index: t_LeftBracket t_PosNumber t_RightBracket { $$ = instance->callbacks.malloc(sizeof(struct operand)); assert($$ != NULL); $$->kind = OPERAND_IMMEDIATE; $$->type = TYPE_INT; $$->bytype.immediate.univ_int = $2; } | t_LeftBracket register_operand t_RightBracket { $$ = $2; assert($2->type == TYPE_INT); } ; /* **************** types *************** */ type_declaration: t_TYPE name t_IS type_list t_Semicolon { $$ = instance->callbacks.malloc( sizeof(struct type_declaration)); assert($$ != NULL); $$->name = $2; $$->elements = $4; $$->elem_count = -1; } ; type_list: type_list t_Comma type { $$ = $1; slist_add($$, $3, instance->callbacks.malloc); } | type { $$ = slist_create(instance->callbacks.malloc); slist_add($$, $1, instance->callbacks.malloc); } ; data_definition: t_DATA opt_resolution data_kind name type t_Semicolon opt_annotation { $$ = instance->callbacks.malloc( sizeof(struct data_definition)); assert($$ != NULL); $$->resolver.name = $2; $$->resolver.container = NULL; $$->name = $4; $$->type = $5; $$->storage = $3; $$->offset = 0; $$->storage_size = 0; $$->annotations = $7; } ; data_kind: t_SIGNAL { $$ = STORAGE_SIGNAL; } | t_VARIABLE { $$ = STORAGE_VARIABLE; } | t_DRIVER { $$ = STORAGE_DRIVER; } ; opt_resolution: /* nothing */ { $$ = NULL; } | t_RESOLVEDBY name { $$ = $2; } ; type: name opt_array opt_default_val opt_annotation { $$ = instance->callbacks.malloc(sizeof(struct type_element)); assert($$ != NULL); $$->name = $1; $$->elements = $2; $$->initial_list = $3; $$->elem_count = -1; $$->offset = 0; $$->annotations = $4; } ; type_name: name { $$ = instance->callbacks.malloc(sizeof(struct type_element)); assert($$ != NULL); $$->name = $1; $$->elements = 1; $$->initial_list = NULL; $$->elem_count = -1; $$->offset = 0; $$->annotations = NULL; } ; opt_array: /* nothing */ { $$ = 1; } | t_LeftBracket t_PosNumber t_RightBracket { $$ = $2; } ; opt_default_val: /* nothing */ { $$ = slist_create(instance->callbacks.malloc); } | t_ValAssign immediate_operand_list { $$ = $2; } ; immediate_operand_list: immediate_operand_list immediate_operand { $$ = $1; slist_add($$, $2, instance->callbacks.malloc); } | immediate_operand { $$ = slist_create(instance->callbacks.malloc); slist_add($$, $1, instance->callbacks.malloc); } ; name: t_Identifier { $$ = $1; } ; /* ****************** annotations ***************** */ opt_annotation: /* nothing */ { $$ = NULL; } | annotation_spec_list { $$ = $1; } ; annotation_spec_list: annotation_spec { $$ = slist_create(instance->callbacks.malloc); slist_add($$, $1, instance->callbacks.malloc); } | annotation_spec_list annotation_spec { $$ = $1; slist_add($$, $2, instance->callbacks.malloc); } ; annotation_spec: annotation_spec_int { $$ = $1; } | annotation_spec_string { $$ = $1; } ; annotation_spec_int: t_AnnotateName t_AnnotateEqSym t_AnnotateInt { $$ = instance->callbacks.malloc( sizeof(struct annotation_spec)); assert($$ != NULL); $$->name = $1; $$->int_value = $3; $$->string_value = NULL; } ; annotation_spec_string: t_AnnotateName t_AnnotateEqSym t_AnnotateString { $$ = instance->callbacks.malloc( sizeof(struct annotation_spec)); assert($$ != NULL); $$->name = $1; $$->string_value = $3; $$->int_value = -1; } ; %% #include "glue-log.h" static void yyerror(struct fauhdli *instance, const char *filename, const char *msg) { /* FIXME line number */ assert(instance->callbacks.log != NULL); instance->callbacks.log(FAUHDLI_LOG_ERROR, "fauhdli", "parser", "%s:%d: Parse error: %s\n", filename, yylineno, msg); } fauhdlc-20130704/interpreter/lookup_symbols.h0000664000175000017500000000114211257125511020575 0ustar potyrapotyra/* $Id: lookup_symbols.h 4698 2009-09-25 11:36:41Z potyra $ * Interpreter library: resolve labels/references. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LOOKUP_SYMBOLS_H_INCLUDED #define __LOOKUP_SYMBOLS_H_INCLUDED #include "fauhdli_private.h" extern void fauhdli_resolve_symbols(struct fauhdli *instance); #endif /* __LOOKUP_SYMBOLS_H_INCLUDED */ fauhdlc-20130704/interpreter/vhdl_sched.c0000664000175000017500000000622311261400724017614 0ustar potyrapotyra/* $Id: vhdl_sched.c 4800 2009-10-02 13:36:20Z potyra $ * * Scheduler for VHDL processes. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "vhdl_sched.h" #include #include #include "glue-log.h" struct vhdl_sched_process { /** callback object instance */ void *s; /** callback to execute the process */ void (*run)(void *s); /** name of the process */ const char *name; }; static void vhdl_sched_destroy_process( struct vhdl_sched_process *p, const struct glue_vhdl_cb *callbacks ) { callbacks->free(p); } struct vhdl_sched * vhdl_sched_create(const struct glue_vhdl_cb *callbacks) { struct vhdl_sched *ret; ret = callbacks->malloc(sizeof(struct vhdl_sched)); assert(ret != NULL); ret->run_q = slset_create(NULL, callbacks->malloc); ret->wait_q = slset_create(NULL, callbacks->malloc); return ret; } void vhdl_sched_destroy( struct vhdl_sched *sched, const struct glue_vhdl_cb *callbacks ) { struct slset_entry *i; assert(sched != NULL); for (i = sched->run_q->first; i != NULL; i = i->next) { vhdl_sched_destroy_process( (struct vhdl_sched_process *)i->data, callbacks); } for (i = sched->wait_q->first; i != NULL; i = i->next) { vhdl_sched_destroy_process( (struct vhdl_sched_process *)i->data, callbacks); } slset_destroy(sched->run_q, callbacks->free); slset_destroy(sched->wait_q, callbacks->free); callbacks->free(sched); } void vhdl_sched_add_process( struct vhdl_sched *sched, void *s, void (*run)(void *s), const char *name, const struct glue_vhdl_cb *callbacks ) { struct vhdl_sched_process *p; p = callbacks->malloc(sizeof(struct vhdl_sched_process)); assert(p != NULL); /* TODO sort by time? */ assert(s != NULL); assert(run != NULL); p->s = s; p->run = run; p->name = name; slset_add(sched->run_q, p, callbacks->malloc); } void vhdl_sched_run( struct vhdl_sched *sched, const struct glue_vhdl_cb *callbacks ) { struct slset_entry *i; for (i = sched->run_q->first; i != NULL; i = i->next) { struct vhdl_sched_process *p = (struct vhdl_sched_process *)i->data; #if 0 /* not needed atm. */ faum_log(FAUM_LOG_DEBUG, "fauhdli", "sched", "running process \"%s\"\n", p->name); #endif p->run(p->s); } slset_move_all( sched->run_q, sched->wait_q, callbacks->malloc, callbacks->free); } bool vhdl_sched_has_runnable(struct vhdl_sched *sched) { return ! slset_empty(sched->run_q); } void vhdl_sched_wakeup( struct vhdl_sched *sched, void *s, const struct glue_vhdl_cb *callbacks ) { struct slset_entry *i; struct vhdl_sched_process *p = NULL; for (i = sched->wait_q->first; i != NULL; i = i->next) { p = (struct vhdl_sched_process *)i->data; if (p->s == s) { break; } } if (p != NULL) { #if 0 /* not needed atm. */ faum_log(FAUM_LOG_DEBUG, "fauhdli", "sched", "waking up %s\n", p->name); #endif slset_remove(sched->wait_q, p, callbacks->free); slset_add(sched->run_q, p, callbacks->malloc); } } fauhdlc-20130704/interpreter/log.h0000664000175000017500000000163711260411052016276 0ustar potyrapotyra/* $Id: log.h 4768 2009-09-29 13:56:58Z potyra $ * * Utilitiy functions to log assertions messages. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LOG_H_INCLUDED #define __LOG_H_INCLUDED #include "fauhdli.h" /** log a character to stdout. * @param callbacks callbacks for logging/scheduler access. * @param level -1 continue message, 0: note, 1: warning, 2: error, * 3: failure. * @param path_name path to instance which requested logging * (usually the stack name). * @param c character to log. */ extern void log_vhdl( const struct glue_vhdl_cb *callbacks, int level, const char *path_name, char c ); #endif /* __LOG_H_INCLUDED */ fauhdlc-20130704/interpreter/util/0000775000175000017500000000000012165333077016331 5ustar potyrapotyrafauhdlc-20130704/interpreter/util/fauhdlstring.h0000664000175000017500000000136511717540733021202 0ustar potyrapotyra/* $Id: fauhdlstring.h 5105 2012-02-17 21:08:43Z potyra $ * * Helper functions for strings. * * Copyright (C) 2012 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FAUHDLSTRING_H #define __FAUHDLSTRING_H #include /** duplicate string src using allocator to obtain memory. * @param src null-terminated string to duplicate. * @param allocator memory allocator (e.g. malloc). * @return duplicated string. */ extern char *fauhdlstrdup(const char *src, void *(*allocator)(size_t)); #endif /* ! __FAUHDLSTRING_H */ fauhdlc-20130704/interpreter/util/fauhdlstring.c0000664000175000017500000000121311717540733021165 0ustar potyrapotyra/* $Id: fauhdlstring.c 5105 2012-02-17 21:08:43Z potyra $ * * Helper functions for strings. * * Copyright (C) 2012 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "fauhdlstring.h" #include #include char * fauhdlstrdup(const char *src, void *(allocator)(size_t)) { char *ret = NULL; size_t len = strlen(src) + 1; ret = allocator(len); assert(ret != NULL); memcpy(ret, src, len); return ret; } fauhdlc-20130704/interpreter/util/slset.c0000664000175000017500000001301611726231007017620 0ustar potyrapotyra/* $Id: slset.c 5111 2012-03-08 22:26:15Z potyra $ * * Tiny implementation of a single linked set. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "slset.h" #include #include #include #if 0 #define DEBUG_MEM_FUNC #endif #ifdef DEBUG_MEM_FUNC extern char etext; extern char _init; /* check if a function pointer is inside the text segment. */ #define CHECK_FUNC_ADDR(fun_ptr) { \ if (fun_ptr != NULL) { \ assert((void *)fun_ptr < (void *)&etext); \ assert((void *)&_init < (void *)fun_ptr); \ } \ } #else /* ! DEBUG_MEM_FUNC */ #define CHECK_FUNC_ADDR(fun_ptr) /* nothing */ #endif /* DEBUG_MEM_FUNC */ static int __attribute__((__const__)) slset_compare_builtin(const void *o1, const void *o2) { if (o1 < o2) { return -1; } if (o1 == o2) { return 0; } return 1; } static void slset_destroy_set(struct slset *s, bool d_data, void (*deallocator)(void *)) { struct slset_entry *tmp; struct slset_entry *i = s->first; while (i != NULL) { tmp = i; i = i->next; if (d_data) { deallocator(tmp->data); } deallocator(tmp); } } struct slset * slset_create( int (*compare)(const void *o1, const void *o2), void *(*allocator)(size_t) ) { struct slset *ret; CHECK_FUNC_ADDR(compare); ret = allocator(sizeof(struct slset)); assert(ret != NULL); ret->compare = compare; if (ret->compare == NULL) { ret->compare = &slset_compare_builtin; } ret->first = NULL; return ret; } void slset_destroy(struct slset *s, void (*deallocator)(void *)) { slset_destroy_set(s, false, deallocator); deallocator(s); } void slset_destroy_data(struct slset *s, void (*deallocator)(void *)) { slset_destroy_set(s, true, deallocator); deallocator(s); } void slset_add( struct slset *s, void *data, void *(*allocator)(size_t) ) { struct slset_entry *entry; struct slset_entry *i; struct slset_entry *last; bool past_entry = false; CHECK_FUNC_ADDR(s->compare); entry = allocator(sizeof(struct slset_entry)); assert(entry != NULL); entry->data = data; if (s->first == NULL) { entry->next = NULL; s->first = entry; return; } /* entries already present. */ last = NULL; for (i = s->first; i != NULL; i = i->next) { int cmp = s->compare(i->data, data); if (cmp > 0) { past_entry = true; break; } if (cmp == 0) { /* entry already present. do nothing. */ return; } last = i; } if (past_entry) { int cmp; if (last == NULL) { entry->next = s->first; s->first = entry; return; } cmp = s->compare(last->data, data); assert(cmp == -1); entry->next = last->next; last->next = entry; return; } /* gone all through the list, but not past the entry where to insert -> insert after tail. */ entry->next = NULL; last->next = entry; /* s->first doesn't change */ } void slset_move_all( struct slset *src, struct slset *dst, void *(*allocator)(size_t), void (*deallocator)(void *) ) { struct slset_entry *i; assert(src != NULL); assert(dst != NULL); assert(src->compare == dst->compare); /* FIXME use a faster implementation */ for (i = src->first; i != NULL; i = i->next) { slset_add(dst, i->data, allocator); } slset_destroy_set(src, false, deallocator); src->first = NULL; } bool slset_empty(const struct slset *s) { return s->first == NULL; } bool slset_contains(const struct slset *haystack, const void *needle) { struct slset_entry *i; CHECK_FUNC_ADDR(haystack->compare); for (i = haystack->first; i != NULL; i = i->next) { int cmp = haystack->compare(i->data, needle); if (cmp == 0) { return true; } if (cmp > 0) { /* already past element */ break; } } return false; } void slset_remove(struct slset *s, const void *data, void (*deallocator)(void *)) { struct slset_entry *i; struct slset_entry *prev; CHECK_FUNC_ADDR(s->compare); prev = s->first; for (i = s->first; i != NULL; i = i->next) { int cmp = s->compare(i->data, data); if (cmp == 0) { /* found */ if (prev == i) { /* first element */ s->first = prev->next; deallocator(i); return; } prev->next = i->next; deallocator(i); return; } if (cmp > 0) { /* past element */ return; } prev = i; } } void slset_clear(struct slset *s, void (*deallocator)(void *)) { struct slset_entry *i; struct slset_entry *n; for (i = s->first; i != NULL; /* nothing */) { n = i; i = i->next; deallocator(n); } s->first = NULL; } void slset_truncate_at( struct slset *s, const void *data, bool del_data, void (*deallocator)(void *) ) { struct slset_entry *i; struct slset_entry *prev = NULL; CHECK_FUNC_ADDR(s->compare); for (i = s->first; i != NULL; i = i->next) { int cmp = s->compare(i->data, data); if (cmp != -1) { break; } prev = i; } /* nothing to delete? */ if (i == NULL) { return; } /* first entry? */ if (prev == NULL) { s->first = NULL; } else { prev->next = NULL; } while (i != NULL) { prev = i; i = i->next; if (del_data) { deallocator(prev->data); } deallocator(prev); } } void slset_debug_print( const struct slset *s, const char *(*print_data)(const void *)) { const struct slset_entry *i; fprintf(stderr, "fauhdli slset: printing set instance %p\n", s); for (i = s->first; i != NULL; i = i->next) { fprintf(stderr, "fauhdli slset: " "tstruct %p, data %s\n", i, print_data(i->data)); } } fauhdlc-20130704/interpreter/util/list.h0000664000175000017500000000200411261377213017445 0ustar potyrapotyra/* $Id: list.h 4799 2009-10-02 13:22:19Z potyra $ * * Generic list structures. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LIST_H_INCLUDED #define __LIST_H_INCLUDED #include /** entry in a single linked list */ struct slist_entry { /** pointer to next element */ struct slist_entry *next; /** pointer to data object */ void *data; }; /** single linked list */ struct slist { /** pointer to first element */ struct slist_entry *first; /** pointer to last element. */ struct slist_entry *tail; }; extern struct slist * slist_create(void *(*allocator)(size_t)); extern void slist_destroy(struct slist *l, void (*deallocator)(void *)); extern void slist_add(struct slist *l, void *data, void *(*allocator)(size_t)); #endif /* __LIST_H_INCLUDED */ fauhdlc-20130704/interpreter/util/list.c0000664000175000017500000000225211261377213017445 0ustar potyrapotyra/* $Id: list.c 4799 2009-10-02 13:22:19Z potyra $ * * Generic list structures. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "list.h" #include #include struct slist * slist_create(void *(*allocator)(size_t)) { struct slist *ret = allocator(sizeof(struct slist)); assert(ret != NULL); ret->first = NULL; ret->tail = NULL; return ret; } void slist_destroy(struct slist *l, void (*deallocator)(void *)) { struct slist_entry *i = l->first; struct slist_entry *tmp; while (i != NULL) { tmp = i; i = i->next; deallocator(tmp); } deallocator(l); } void slist_add(struct slist *l, void *data, void *(*allocator)(size_t)) { struct slist_entry *entry = allocator(sizeof(struct slist_entry)); assert(entry != NULL); assert(l != NULL); entry->data = data; entry->next = NULL; if (l->tail == NULL) { l->first = entry; l->tail = entry; } else { l->tail->next = entry; l->tail = entry; } } fauhdlc-20130704/interpreter/util/slset.h0000664000175000017500000001033611726230621017630 0ustar potyrapotyra/* $Id: slset.h 5110 2012-03-08 22:24:17Z potyra $ * * Structure for a single linked set. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SLSET_H_INCLUDED #define __SLSET_H_INCLUDED #include #include /** entry in a single linked set. */ struct slset_entry { /** pointer to next element. */ struct slset_entry *next; /** data object */ void *data; }; /** single linked set, stores element in ascending order. */ struct slset { /** pointer to first element */ struct slset_entry *first; /** comparison operator for data objects (may be NULL) * @param o1 first object to compare * @param o2 second object to compare * @return -1 if o1 < o2, 0 if o1 == o2, 1 otherwise. */ int (*compare)(const void *o1, const void *o2); }; /** create a single linked set. * @param comparison operator for ordering (may be NULL, then < and == will * get used). This must be a function without side effects * (__attribute__((__pure__))). * @param allocator: function to allocate memory (e.g. malloc). * @return created single linked set. */ extern struct slset * slset_create( int (*compare)(const void *o1, const void *o2), void *(*allocator)(size_t) ); /** destroy a single linked set. * @param s set instance * @param deallocator deallocator (e.g. free) */ extern void slset_destroy(struct slset *s, void (*deallocator)(void *)); /** destroy a single linked set, calling free for each data entry. * @param s set instance * @param deallocator deallocator (e.g. free) */ extern void slset_destroy_data(struct slset *s, void (*deallocator)(void *)); /** add data to the set, in case it doesn't exist yet, otherwise a NOOP. * @param s set instance. * @param data data object. * @param allocator function to allocate memory (e.g. malloc) */ extern void slset_add( struct slset *s, void *data, void *(*allocator)(size_t) ); /** add all entries from src to dst, assuming the compare functions are * identical. All entries get removed from src. * @param src source set instance. * @param dst destination set instance. * @param allocator function to allocate memory (e.g. malloc) * @param deallocator function to free memory (e.g. free) */ extern void slset_move_all( struct slset *src, struct slset *dst, void *(*allocator)(size_t), void (*deallocator)(void *) ); /** Check if the set is empty. * @param s set to check. * @return true, if the set is empty, false otherwise. */ extern bool slset_empty(const struct slset *s); /** Check if needle is in haystack. * @param haystack set to check if needle is an element of. * @param needle look for needle in haystack. * @return true, if needle is in haystack. */ extern bool slset_contains(const struct slset *haystack, const void *needle); /** remove data from stack. * @param s set instance. * @param data data to remove from the set * @param deallocator function to free memory (e.g. free) */ extern void slset_remove(struct slset *s, const void *data, void (*deallocator)(void *)); /** remove all entries from given set * @param s set to clear. * @param deallocator function to free memory (e.g. free) */ extern void slset_clear(struct slset *s, void (*deallocator)(void *)); /** remove all elements which are equal or greater than data according to * the comparison function. * @param s set instance. * @param data compare the entries with data, remove everything which * doesn't return -1 from the comparison function with data * as second argument. * @param del_data true, if the truncated data should be freed as well. * @param deallocator function to free memory (e.g. free) */ extern void slset_truncate_at( struct slset *s, const void *data, bool del_data, void (*deallocator)(void *) ); /** debugging function to print out the set. * @param s set in question. * @param print_data function to print the data. */ extern void slset_debug_print( const struct slset *s, const char *(*print_data)(const void *) ); #endif /* __SLSET_H_INCLUDED */ fauhdlc-20130704/interpreter/lookup_symbols.c0000664000175000017500000004315511717543645020617 0ustar potyrapotyra/* $Id: lookup_symbols.c 5108 2012-02-17 21:33:25Z potyra $ * Interpreter library: resolve labels/references. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "lookup_symbols.h" #include "kernel.h" /* for driver/signal struct */ #include #include #include #include #include "glue-log.h" #include "fauhdlstring.h" #define ARRAY_SIZE(t) (sizeof t / sizeof(t[0])) struct symbol_table_label { const char *name; struct slist_entry *target; }; struct symbol_table_type { const char *name; struct type_declaration *type; }; struct symbol_table_container_ref { const char *name; unsigned int nesting; struct code_container *container; struct symbol_table_container_ref *next; struct symbol_table_container_ref *prev; }; struct symbol_table_data_ref { const char *name; unsigned int nesting; const struct data_definition *definition; struct symbol_table_data_ref *next; struct symbol_table_data_ref *prev; }; struct symbol_table { unsigned int nlabels; unsigned int ntypes; /* labels are only valid in one container's text segment, * so these will just be stuffed into one array */ struct symbol_table_label labels[10000]; struct symbol_table_type type[1000]; /* container head and tail pointer */ struct symbol_table_container_ref *container_head; struct symbol_table_container_ref *container_tail; /* data head and tail pointer */ struct symbol_table_data_ref *data_head; struct symbol_table_data_ref *data_tail; /* hacky store the callbacks there for logging */ const struct glue_vhdl_cb *callbacks; }; static void symbol_resolve_type_elements( const struct symbol_table *symtab, struct type_declaration *type_decl ); static void symbol_label_add( struct symbol_table *symtab, const char *name, struct slist_entry *entry ) { assert(symtab->nlabels < ARRAY_SIZE(symtab->labels)); symtab->labels[symtab->nlabels].name = name; symtab->labels[symtab->nlabels].target = entry; symtab->nlabels++; } static void symtab_clear_labels(struct symbol_table *symtab) { symtab->nlabels = 0; } /** remove every container reference entry that has a nesting level * >= nesting_level. * @param symtab symbol table instance. * @param nesting_level remove entries >= nesting_level. */ static void symtab_remove_container_refs( struct symbol_table *symtab, unsigned int nesting_level ) { struct symbol_table_container_ref *i = symtab->container_tail; struct symbol_table_container_ref *j; while (i != NULL) { if (i->nesting < nesting_level) { break; } j = i; i = i->prev; symtab->callbacks->free(j); } if (i == NULL) { symtab->container_head = NULL; symtab->container_tail = NULL; } else { i->next = NULL; symtab->container_tail = i; } } static void symtab_register_container_ref( struct symbol_table *symtab, struct code_container *container, unsigned int nesting_level ) { struct symbol_table_container_ref *ref; ref = symtab->callbacks->malloc( sizeof(struct symbol_table_container_ref)); assert(ref != NULL); ref->name = container->name; ref->nesting = nesting_level; ref->container = container; ref->next = NULL; ref->prev = symtab->container_tail; if (symtab->container_tail == NULL) { symtab->container_head = ref; symtab->container_tail = ref; } else { assert(symtab->container_tail->nesting <= nesting_level); symtab->container_tail->next = ref; symtab->container_tail = ref; } } static void symtab_register_data_ref( struct symbol_table *symtab, const struct data_definition *data, unsigned int nesting_level ) { struct symbol_table_data_ref *ref; ref = symtab->callbacks->malloc(sizeof(struct symbol_table_data_ref)); assert(ref != NULL); assert(data->nesting_level == nesting_level); ref->name = data->name; ref->nesting = nesting_level; ref->next = NULL; ref->prev = symtab->data_tail; ref->definition = data; if (symtab->data_tail == NULL) { symtab->data_tail = ref; symtab->data_head = ref; } else { assert(symtab->data_tail->nesting <= nesting_level); symtab->data_tail->next = ref; symtab->data_tail = ref; } } static void symtab_remove_data_refs( struct symbol_table *symtab, unsigned int nesting_level ) { struct symbol_table_data_ref *i = symtab->data_tail; struct symbol_table_data_ref *j; while (i != NULL) { if (i->nesting < nesting_level) { break; } j = i; i = i->prev; symtab->callbacks->free(j); } if (i == NULL) { symtab->data_tail = NULL; symtab->data_head = NULL; } else { symtab->data_tail = i; i->next = NULL; } } static void symbol_type_add( struct symbol_table *symtab, struct type_declaration *type ) { assert(symtab->ntypes < ARRAY_SIZE(symtab->type)); symtab->type[symtab->ntypes].name = type->name; symtab->type[symtab->ntypes].type = type; symtab->ntypes++; } static struct type_declaration * symbol_lookup_type( const struct symbol_table *symtab, const char *name ) { unsigned int i; for (i = 0; i < symtab->ntypes; i++) { if (strcmp(name, symtab->type[i].name) == 0) { return symtab->type[i].type; } } return NULL; } /** resolve one type element * @param symtab symbol table instance. * @param elem element to resolve * @param offset number of basic element before this type element. * @return number of basic elements of this type element. */ static int symbol_resolve_type_element( const struct symbol_table *symtab, struct type_element *elem, int offset ) { struct type_declaration *type_decl; assert(elem != NULL); elem->offset = offset; type_decl = symbol_lookup_type(symtab, elem->name); if (type_decl == NULL) { symtab->callbacks->log( FAUHDLI_LOG_ERROR, "fauhdli", "symboltable", "Cannot lookup type %s\n", elem->name); return 0; } /* type already seen? */ if (type_decl->elem_count == -1) { symbol_resolve_type_elements(symtab, type_decl); assert(type_decl->elem_count != -1); } elem->elem_count = elem->elements * type_decl->elem_count; elem->type = type_decl; return elem->elem_count; } static void symbol_resolve_type_elements( const struct symbol_table *symtab, struct type_declaration *type_decl ) { struct slist_entry *i; int offset = 0; if (type_decl->elements == NULL) { /* must be a builtin type. */ assert(type_decl->elem_count != -1); return; } for (i = type_decl->elements->first; i != NULL; i = i->next) { struct type_element *elem = (struct type_element *)i->data; offset += symbol_resolve_type_element(symtab, elem, offset); } type_decl->elem_count = offset; } static size_t symtab_get_data_size(const struct data_definition *data) { size_t basic_size = 0; if (data->type->elem_count < 0) { /* can only happen, if resolution failed before */ assert(0); return 0; } basic_size = sizeof(union fauhdli_value); return basic_size * data->type->elem_count; } /** determine the complete storage size of one segment. * @param seg data or transfer segmenet * @return storage size of the segment in bytes. */ static size_t symtab_get_seg_size(struct slist *seg) { struct slist_entry *i; size_t offset = 0; size_t sz; for (i = seg->first; i != NULL; i = i->next) { struct data_definition *d = (struct data_definition *)i->data; d->offset = offset; sz = symtab_get_data_size(d); d->storage_size = sz; offset += sz; } return offset; } static const struct data_definition * symbol_data_reference_resolve( const struct symbol_table *symtab, const char *name ) { struct symbol_table_data_ref *i; for (i = symtab->data_head; i != NULL; i = i->next) { if (strcmp(i->name, name) == 0) { assert(i->definition != NULL); return i->definition; } } symtab->callbacks->log( FAUHDLI_LOG_WARNING, "fauhdli", "symboltable", "cannot resolve reference \"%s\"\n", name); return NULL; } static const struct symbol_table_label * symbol_label_resolve(const struct symbol_table *symtab, const char *name) { unsigned int i; for (i = 0; i < symtab->nlabels; i++) { if (strcmp(name, symtab->labels[i].name) == 0) { return &symtab->labels[i]; } } symtab->callbacks->log( FAUHDLI_LOG_ERROR, "fauhdli", "symboltable", "cannot resolve label \"%s\"\n", name); return NULL; } static void symtab_operand_container_resolve( const struct symbol_table *symtab, struct operand *op ) { struct symbol_table_container_ref *i; const char *name; assert(op->kind == OPERAND_REFERENCE); name = op->bytype.data.name; for (i = symtab->container_head; i != NULL; i = i->next) { if (strcmp(i->name, name) == 0) { op->bytype.data.container = i->container; op->bytype.data.ref = NULL; return; } } symtab->callbacks->log(FAUHDLI_LOG_ERROR, "fauhdli", "symbol_table", "could not resolve function/container %s\n", name); op->bytype.data.container = NULL; } static void symtab_resolver_resolve( const struct symbol_table *symtab, struct data_definition *data ) { struct symbol_table_container_ref *i; if (data->resolver.name == NULL) { return; } for (i = symtab->container_head; i != NULL; i = i->next) { if (strcmp(i->name, data->resolver.name) == 0) { data->resolver.container = i->container; symtab->callbacks->free(data->resolver.name); return; } } symtab->callbacks->log(FAUHDLI_LOG_ERROR, "fauhdli", "symbol_table", "could not resolver resolution function %s\n", data->resolver.name); } static void symtab_resolve_transfer( const struct code_container *container, struct operand *tref, const struct glue_vhdl_cb *callbacks ) { struct slist_entry *i; struct data_definition *d; assert(tref->kind == OPERAND_REFERENCE); if (container->transfer_segment == NULL) { callbacks->log(FAUHDLI_LOG_ERROR, "fauhdli", "symboltable", "Cannot resolve transfer reference \"%s\", since " "\"%s\" has no transfer paremeters.\n", tref->bytype.data.name, container->name); return; } for (i = container->transfer_segment->first; i != NULL; i = i->next) { d = (struct data_definition *)i->data; if (strcmp(d->name, tref->bytype.data.name) == 0) { /* matching entry */ tref->bytype.data.ref = d; tref->bytype.data.container = NULL; return; } } callbacks->log(FAUHDLI_LOG_ERROR, "fauhdli", "symboltable", "cannot resolve transfer element \"%s\" in " "container \"%s\"\n", tref->bytype.data.name, container->name); } static void symtab_operand_resolve( struct symbol_table *symtab, struct operand *op ) { const struct symbol_table_label *entry; const struct data_definition *ref; switch (op->kind) { case OPERAND_TARGET: entry = symbol_label_resolve(symtab, op->bytype.target.name); op->bytype.target.ref = entry->target; break; case OPERAND_REFERENCE: ref = symbol_data_reference_resolve(symtab, op->bytype.data.name); op->bytype.data.ref = ref; op->bytype.data.container = NULL; break; default: break; } } static void symtab_opcode_resolve( struct symbol_table *symtab, struct opcode *opcode ) { const struct annotation_spec *spec = fauhdli_find_annotation("foreign", opcode->annotations); /* special handling for opcodes that have container references */ switch (opcode->kind) { case OPCODE_BEGINTRANS: case OPCODE_ENDTRANS: case OPCODE_CALL: case OPCODE_PROC: /* op1: container */ assert(opcode->op1 != NULL); if (spec != NULL) { /* don't resolve the container for foreign * function call opcodes */ return; } symtab_operand_container_resolve(symtab, opcode->op1); return; case OPCODE_SETPARAM: /* op2: container, op3: transfer element of container op2 */ assert(opcode->op1 != NULL); assert(opcode->op2 != NULL); assert(opcode->op3 != NULL); symtab_operand_resolve(symtab, opcode->op1); if (spec != NULL) { /* don't resolve containers of foreign setparam */ return; } symtab_operand_container_resolve(symtab, opcode->op2); assert(opcode->op2->kind == OPERAND_REFERENCE); assert(opcode->op2->bytype.data.container != NULL); symtab_resolve_transfer( opcode->op2->bytype.data.container, opcode->op3, symtab->callbacks); return; case OPCODE_GETPARAM: /* op2: container, op1: transfer element of container op2 */ assert(opcode->op1 != NULL); assert(opcode->op2 != NULL); assert(opcode->op3 != NULL); symtab_operand_resolve(symtab, opcode->op3); if (spec != NULL) { /* don't resolve containers of foreign setparam */ return; } symtab_operand_container_resolve(symtab, opcode->op2); assert(opcode->op2->kind == OPERAND_REFERENCE); assert(opcode->op2->bytype.data.container != NULL); symtab_resolve_transfer( opcode->op2->bytype.data.container, opcode->op1, symtab->callbacks); return; case OPCODE_AOFFSET: case OPCODE_ROFFSET: assert(opcode->indexed_type != NULL); symbol_resolve_type_element(symtab, opcode->indexed_type, 0); break; default: break; } if (opcode->op1 != NULL) { symtab_operand_resolve(symtab, opcode->op1); } if (opcode->op2 != NULL) { symtab_operand_resolve(symtab, opcode->op2); } if (opcode->op3 != NULL) { symtab_operand_resolve(symtab, opcode->op3); } } static void symtab_register_labels( struct symbol_table *symtab, struct slist *text_seg ) { struct slist_entry *i; struct opcode *opcode; for (i = text_seg->first; i != NULL; i = i->next) { opcode = (struct opcode*)i->data; switch (opcode->kind) { case OPCODE_LABEL: assert(opcode->label != NULL); symbol_label_add(symtab, opcode->label, i); break; default: break; } } } static void symtab_resolve_text_seg( struct symbol_table *symtab, struct slist *seg ) { struct slist_entry *i; for (i = seg->first; i != NULL; i = i->next) { symtab_opcode_resolve( symtab, (struct opcode*)i->data ); } } static void symtab_register_data( struct symbol_table *symtab, struct slist *seg, unsigned int nesting_level, enum segment_kind loc ) { struct slist_entry *i; struct data_definition *d; for (i = seg->first; i != NULL; i = i->next) { d = (struct data_definition *)i->data; d->nesting_level = nesting_level; d->loc = loc; symtab_register_data_ref(symtab, d, nesting_level); symbol_resolve_type_element(symtab, d->type, 0); symtab_resolver_resolve(symtab, d); } } static void symtab_register_types(struct symbol_table *symtab, struct slist *seg) { struct slist_entry *i; struct type_declaration *t; for (i = seg->first; i != NULL; i = i->next) { t = (struct type_declaration *)i->data; symbol_type_add(symtab, t); symbol_resolve_type_elements(symtab, t); } } static void symtab_walk_container( struct symbol_table *symtab, struct code_container *container, unsigned int nesting_level ) { struct slist_entry *i; container->nesting_level = nesting_level; symtab_register_container_ref(symtab, container, nesting_level); if (container->type_definitions != NULL) { symtab_register_types(symtab, container->type_definitions); } if (container->transfer_segment != NULL) { symtab_register_data(symtab, container->transfer_segment, nesting_level, SEGMENT_TRANSFER); container->transfer_size = symtab_get_seg_size(container->transfer_segment); } else { container->transfer_size = 0; } if (container->stack_segment != NULL) { symtab_register_data(symtab, container->stack_segment, nesting_level, SEGMENT_STACK); container->stack_size = symtab_get_seg_size(container->stack_segment); } else { container->stack_size = 0; } if (container->sub_containers != NULL) { for (i = container->sub_containers->first; i != NULL; i = i->next) { symtab_walk_container( symtab, (struct code_container*)i->data, nesting_level + 1 ); } } if (container->text_segment != NULL) { symtab_register_labels( symtab, container->text_segment ); symtab_resolve_text_seg(symtab, container->text_segment); symtab_clear_labels(symtab); } symtab_remove_container_refs(symtab, nesting_level + 1); symtab_remove_data_refs(symtab, nesting_level); } static void symbol_table_register_builtins( struct fauhdli *instance, struct symbol_table *symtab ) { /* universal_integer */ static struct type_declaration univ_int_t = { .elements = NULL, /* internal */ .elem_count = 1 }; /* universal_real */ static struct type_declaration univ_real_t = { .elements = NULL, /* internal */ .elem_count = 1 }; static struct type_declaration base_pointer_t = { .elements = NULL, /* internal */ .elem_count = 1 }; /* FIXME we don't want to free these (const problem). */ univ_int_t.name = fauhdlstrdup("universal_integer", instance->callbacks.malloc); slset_add( instance->cleanup_ptrs, univ_int_t.name, symtab->callbacks->malloc); univ_real_t.name = fauhdlstrdup("universal_real", instance->callbacks.malloc); slset_add( instance->cleanup_ptrs, univ_real_t.name, symtab->callbacks->malloc); base_pointer_t.name = fauhdlstrdup("__pointer__", instance->callbacks.malloc); slset_add( instance->cleanup_ptrs, base_pointer_t.name, symtab->callbacks->malloc); symbol_type_add(symtab, &univ_int_t); symbol_type_add(symtab, &univ_real_t); symbol_type_add(symtab, &base_pointer_t); /* TODO: builtin functions */ } static void symbol_table_init(struct fauhdli *instance, struct symbol_table *symtab) { symtab->nlabels = 0; symtab->ntypes = 0; symtab->container_head = NULL; symtab->container_tail = NULL; symtab->data_head = NULL; symtab->data_tail = NULL; symtab->callbacks = &instance->callbacks; symbol_table_register_builtins(instance, symtab); } void fauhdli_resolve_symbols(struct fauhdli *instance) { struct symbol_table symtab; assert(instance->container != NULL); symbol_table_init(instance, &symtab); symtab_walk_container(&symtab, instance->container, 1); symtab_remove_container_refs(&symtab, 0); } fauhdlc-20130704/interpreter/Makefile.am0000664000175000017500000000216711717541003017406 0ustar potyrapotyra# $Id: Makefile.am 5106 2012-02-17 21:09:23Z potyra $ INCLUDES=-I$(srcdir)/glue -I$(srcdir)/util -I$(top_srcdir)/util -I$(top_srcdir) # make sure that icparser.c will get built before anything gets compiled. BUILT_SOURCES=icparser.c CLEANFILES=icparser.h icparser.c icscanner.c bin_PROGRAMS=fauhdli lib_LIBRARIES=libfauhdli.a libfauhdli_a_SOURCES= \ icparser.y \ icscanner.l \ fauhdli.c \ kernel.c \ signals.c \ vhdl_sched.c \ lookup_symbols.c \ trace.c \ log.c \ util/fauhdlstring.c \ util/list.c \ util/slset.c \ ../util/mangle_names.c \ glue/glue-log.c \ glue/glue-main.c \ \ glue/glue-log.h \ glue/glue-main.h \ glue/glue-vhdl.h \ icparser.h \ kernel.h \ fauhdli_private.h \ log.h \ lookup_symbols.h \ signals.h \ trace.h \ util/fauhdlstring.h \ util/list.h \ util/slset.h \ vhdl_sched.h include_HEADERS=\ fauhdli.h\ ../util/basetypes.h noinst_LIBRARIES=libglue.a libglue_a_SOURCES=\ glue/glue-vhdl.c fauhdli_SOURCES=\ interpreter.c fauhdli_LDADD=\ libfauhdli.a\ libglue.a devel: $(CURDIR)/$(top_srcdir)/misc/install_ln.sh $(MAKE) install INSTALL=$< .PHONY: devel fauhdlc-20130704/interpreter/kernel.h0000664000175000017500000000266711260161202017000 0ustar potyrapotyra/* $Id: kernel.h 4758 2009-09-28 16:21:22Z potyra $ * * Interpreter kernel. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __KERNEL_H_INCLUDED #define __KERNEL_H_INCLUDED #include "fauhdli_private.h" extern void fauhdli_kernel_destroy(struct fauhdli *instance); extern void fauhdli_kernel_init(struct fauhdli *instance, const char *top_entity); /** resolve driving values drv_values to ret with the given resolution * function. * * @param instance fauhdli instance. * @param resolver container of the pure resolution function. * @param ret return value is stored there * @param drv_values array of driving values. * @param sz size of array. */ extern void fauhdli_kernel_resolve( struct fauhdli *instance, const struct code_container *resolver, union fauhdli_value *ret, union fauhdli_value *drv_values, size_t sz ); /** Function to run the simulation cycle for the current simulation * time. Should only be called by kernel itself and otherwise get * registered as a callback if a foreign driver updates it's driving * value. * * @param _instance struct fauhdli instance pointer. */ void fauhdli_kernel_simulation_cycle(void *_instance); #endif /* __KERNEL_H_INCLUDED */ fauhdlc-20130704/interpreter/trace.c0000664000175000017500000001603511343747723016627 0ustar potyrapotyra/* $Id: trace.c 4924 2010-03-04 15:20:51Z potyra $ * * Utilities for writing to a VCD file. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "trace.h" #include "mangle_names.h" #include #include #include #include #include "glue-log.h" #include #include #define INTERPRETER_VERSION "fauhdli 0.0alpha1" #define RESOLUTION_UNIT "fs" #define RESOLUTION_SCALE (1000000000000000ull / (1ull << 32)) enum trace_type_kind { TRACE_TYPE_INT = TYPE_INT, TRACE_TYPE_FLOAT = TYPE_FLOAT, TRACE_TYPE_STDLOGIC }; struct trace_sig_wrapper { /** pointer to the signal in question */ const union fauhdli_value *sigptr; char id_code; enum trace_type_kind type; int array_size; }; static const char * vcd_get_hex(universal_integer num) { static char ret[65] = { '\0' }; int bit; int dst = 0; bool seen = false; for (bit = 63; bit >= 0; bit--) { if ((num & (1ULL << bit)) == 0) { ret[dst] = '0'; } else { ret[dst] = '1'; seen = true; } if (seen) { dst++; } } ret[dst] = '\0'; if (dst == 0) { ret[0] = '0'; ret[1] = '\0'; } return ret; } static const char * vcd_get_var_type(enum trace_type_kind k) { switch (k) { case TRACE_TYPE_INT: return "integer"; case TRACE_TYPE_STDLOGIC: return "tri"; case TRACE_TYPE_FLOAT: return "real"; default: assert(false); } } static void vcd_add_sig( FILE *f, const char *name, char id_code, enum trace_type_kind type, int display_bits ) { size_t sz; char buf[4096]; char *c; int ret; ret = demangle_name(name, buf, sizeof(buf)); assert(ret >= 0); assert((size_t)ret < sizeof(buf)); /* replace ":" with ".", seems like gtkwave matches hierarchy */ for (c = strchr(buf, ':'); c != NULL; c = strchr(buf, ':')) { *c = '.'; } switch (type) { case TYPE_INT: sz = sizeof(universal_integer) * 8; break; case TRACE_TYPE_FLOAT: sz = sizeof(universal_real) * 8; break; case TRACE_TYPE_STDLOGIC: break; default: assert(0); } if (display_bits != -1) { sz = (size_t)display_bits; } fprintf(f, "$var %s %zd %c %s $end\n", vcd_get_var_type(type), sz, id_code, buf ); } static void vcd_write_header(FILE *f) { fprintf(f, "$version %s\n", INTERPRETER_VERSION); fprintf(f, "$end\n"); fprintf(f, "$timescale %lld %s\n", RESOLUTION_SCALE, RESOLUTION_UNIT); fprintf(f, "$end\n"); } static void vcd_end_header(FILE *f) { fprintf(f, "$end\n"); } static void vcd_dump_stdlogic(FILE *f, const struct trace_sig_wrapper *tw) { static const char std_logic_vals[] = "ux01zwlh-"; int i; if (1 < tw->array_size) { fprintf(f, "b"); } for (i = 0; i < tw->array_size; i++) { const struct signal * const sig = (const struct signal *)tw->sigptr[i].pointer; assert(sig->value.univ_int < strlen(std_logic_vals)); fprintf(f, "%c", std_logic_vals[sig->value.univ_int]); } if (1 < tw->array_size) { fprintf(f, " "); } fprintf(f, "%c\n", tw->id_code); } static void vcd_dump_var(FILE *f, const struct trace_sig_wrapper *tw) { switch (tw->type) { case TRACE_TYPE_INT: { const struct signal * const sig = (const struct signal *)tw->sigptr[0].pointer; fprintf(f, "b%s %c\n", vcd_get_hex(sig->value.univ_int), tw->id_code); break; } case TRACE_TYPE_FLOAT: /* TODO */ assert(0); break; case TRACE_TYPE_STDLOGIC: vcd_dump_stdlogic(f, tw); break; default: assert(0); } } static enum trace_type_kind trace_get_type( enum type_kind type, const char *override ) { if (strcmp(override, "std_ulogic") == 0) { return TRACE_TYPE_STDLOGIC; } switch (type) { case TYPE_INT: return TRACE_TYPE_INT; break; case TYPE_FLOAT: return TRACE_TYPE_FLOAT; break; default: /* not supported */ assert(0); } /* unreached */ return TYPE_INT; } static void trace_end_header(struct trace_t *s) { const struct slist_entry *i; vcd_end_header(s->output); s->header_written = true; /* write initial values */ fprintf(s->output, "$dumpvars\n"); for (i = s->traced_sigs->first; i != NULL; i = i->next) { const struct trace_sig_wrapper *tw = (const struct trace_sig_wrapper *)i->data; vcd_dump_var(s->output, tw); } fprintf(s->output, "$end\n"); } static bool trace_can_trace(const struct trace_sig_wrapper *tw) { switch (tw->type) { case TRACE_TYPE_STDLOGIC: /* arrays supported */ return true; case TRACE_TYPE_FLOAT: /* not supported at all yet */ return false; default: break; } /* only non-arrays supported */ return tw->array_size == 1; } struct trace_t * trace_create(const char *trace_file, const struct glue_vhdl_cb *callbacks) { struct trace_t *ret = callbacks->malloc(sizeof(struct trace_t)); assert(ret != NULL); ret->traced_sigs = slist_create(callbacks->malloc); ret->output = fopen(trace_file, "w"); if (ret->output == NULL) { callbacks->log(FAUHDLI_LOG_ERROR, "fauhdli", "tracer", "cannot created output file %s: %s\n", trace_file, strerror(errno)); assert(0); } ret->ident_code = 33; /* ident code is in range 33-126 */ ret->header_written = false; vcd_write_header(ret->output); return ret; } void trace_destroy(struct trace_t *s, const struct glue_vhdl_cb *callbacks) { int ret; struct slist_entry *i; assert(s != NULL); for (i = s->traced_sigs->first; i != NULL; i = i->next) { callbacks->free(i->data); } slist_destroy(s->traced_sigs, callbacks->free); ret = fclose(s->output); assert(ret == 0); callbacks->free(s); } void trace_add_signal( struct trace_t *s, const union fauhdli_value *sigptr, const char *name, enum type_kind type, int display_bits, const char *display_type, const struct glue_vhdl_cb *callbacks, int array_size ) { struct trace_sig_wrapper *tw = callbacks->malloc(sizeof(struct trace_sig_wrapper)); assert(tw != NULL); assert(! s->header_written); tw->id_code = s->ident_code; if (tw->id_code > 126) { callbacks->log(FAUHDLI_LOG_WARNING, "fauhdli", "tracer", "Not tracing signal %s, out of ident codes.\n", name); callbacks->free(tw); return; } tw->type = trace_get_type(type, display_type); tw->sigptr = sigptr; tw->array_size = array_size; if (! trace_can_trace(tw)) { callbacks->log(FAUHDLI_LOG_WARNING, "fauhdli", "tracer", "Not tracing singal %s: not yet supported.\n", name); callbacks->free(tw); return; } s->ident_code++; if (tw->type == TRACE_TYPE_STDLOGIC) { display_bits = array_size; } vcd_add_sig(s->output, name, tw->id_code, tw->type, display_bits); slist_add(s->traced_sigs, tw, callbacks->malloc); } void trace_time_advance(struct trace_t *s, universal_integer sim_time) { struct slist_entry *i; if (! s->header_written) { trace_end_header(s); } for (i = s->traced_sigs->first; i != NULL; i = i->next) { const struct trace_sig_wrapper * const tw = (const struct trace_sig_wrapper * const)i->data; vcd_dump_var(s->output, tw); } fprintf(s->output, "#%" PRIi64 "\n", sim_time); } fauhdlc-20130704/interpreter/interpreter.c0000664000175000017500000000776311306223547020074 0ustar potyrapotyra/* $Id: interpreter.c 4867 2009-12-04 15:14:47Z potyra $ * Main interpreter program. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #ifndef _GNU_SOURCE #define _GNU_SOURCE #include #undef _GNU_SOURCE #else /* _GNU_SOURCE already defined */ #include #endif /* _GNU_SOURCE not defined? */ #include "fauhdli_private.h" #include "glue/glue-vhdl.h" #include "glue/glue-log.h" #include "glue/glue-main.h" static int run_fauhdli( const char *parse_file, const char *top_entity, const char *trace_file, struct slist *trace_ents, bool debug ) { struct fauhdli *instance; int ret; void *fi; static const struct glue_vhdl_cb cb = { /* memory related (libc) */ .malloc = malloc, .free = free, /* scheduler related (glue-main.c) */ .time_virt = fauhdli_time_virt, .time_call_at = fauhdli_time_call_at, .time_call_delete = fauhdli_time_call_delete, .quit = fauhdli_simulation_quit, /* logging */ .log = (void (*)(int, const char *, const char *, const char *, ...))fauhdli_log, /* foreign components related */ .comp_create = glue_vhdl_comp_create, .arch_create = glue_vhdl_arch_create, .signal_create = glue_vhdl_create_signal, .arch_init = glue_vhdl_arch_init, .drv_set = glue_vhdl_set, .proc_set = glue_vhdl_proc_set, .proc_call = glue_vhdl_proc_call, .connect_out = glue_vhdl_connect_out, .connect_in = glue_vhdl_connect_in, .comp_init = glue_vhdl_comp_init, .comp_port_connect = glue_vhdl_comp_port_connect, .arch_port_connect = glue_vhdl_arch_port_connect, .comp_generic_nonarray_set = glue_vhdl_comp_generic_nonarray_set, .arch_generic_nonarray_set = glue_vhdl_arch_generic_nonarray_set, .comp_generic_array_set = glue_vhdl_comp_generic_array_set, .arch_generic_array_set = glue_vhdl_arch_generic_array_set }; fi = glue_vhdl_create(); instance = fauhdli_create(parse_file, trace_file, debug, &cb, fi); instance->trace_list = trace_ents; fauhdli_init(instance, top_entity); ret = fauhdli_main_event_loop(); fauhdli_destroy(instance); glue_vhdl_destroy(fi); return ret; } static void usage(void) { fprintf(stderr, "fauhdli [options] FILE\n"); fprintf(stderr, " Interprete commands from FILE.\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -s ENTITY, --simulate=ENTITY Start simulation " "with ENTITY as top entity.\n"); fprintf(stderr, " -o VCDFILE, --output=VCDFILE Output trace to "); fprintf(stderr, "VCDFILE.\n"); fprintf(stderr, " -d, --debug enable debug " "output\n"); fprintf(stderr, " -t, --trace=ENTITY Trace all signals " "in ENTITY\n"); fprintf(stderr, "\n"); } int main(int argc, char **argv) { const char *parse_file = NULL; const char *top_entity = NULL; const char *trace_file = NULL; int c; bool debug = false; int ret; struct slist *trace_ents; struct option l_opts[] = { {"simulate", 1, NULL, 's'}, {"output", 1, NULL, 'o'}, {"debug", 0, NULL, 'd'}, {"trace", 1, NULL, 't'}, {0, 0, 0, 0} }; trace_ents = slist_create(malloc); for (;;) { c = getopt_long(argc, argv, "s:o:dt:", l_opts, NULL); if (c == -1) { break; } switch (c) { case 's': top_entity = optarg; break; case 'o': trace_file = optarg; break; case 'd': debug = true; break; case 't': slist_add(trace_ents, (void *)optarg, malloc); break; default: usage(); return EXIT_FAILURE; } } if (argc - optind != 1) { usage(); return EXIT_FAILURE; } if ((trace_file == NULL) && (trace_ents->first != NULL)) { usage(); return EXIT_FAILURE; } parse_file = argv[optind]; ret = run_fauhdli( parse_file, top_entity, trace_file, trace_ents, debug); slist_destroy(trace_ents, free); return ret; } fauhdlc-20130704/interpreter/log.c0000664000175000017500000000434711263130442016276 0ustar potyrapotyra/* $Id: log.c 4812 2009-10-07 15:17:54Z potyra $ * * Utilitiy functions to log assertions messages. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "log.h" #include #include "glue-log.h" #include "glue-main.h" #include #include #include #include #include #include #include "mangle_names.h" /* FIXME ripped from glue-main */ #define TIME_HZ (1ULL << 32) static void log_begin( const struct glue_vhdl_cb *callbacks, const char *lvl_msg, const char *path_name ) { struct timeval tv; struct tm *tm; int ret; static char demangled[2048]; tv.tv_sec = callbacks->time_virt() / TIME_HZ; tv.tv_usec = ((callbacks->time_virt() % TIME_HZ) * 1000000) / TIME_HZ; /* Convert the time into a little more useful structure. */ tm = localtime(&tv.tv_sec); if (tm == NULL) { perror("Couldn't break up system time"); exit(1); } ret = demangle_name(path_name, demangled, sizeof(demangled)); assert(ret >= 0); /* Generate the Oracle timestamp. */ ret = fprintf(stdout, "%s: %.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.6d %s in ", lvl_msg, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (unsigned int)tv.tv_usec, demangled ); if (ret < 0) { perror("Timestamp formatting error"); exit(1); } } #undef TIME_HZ void log_vhdl( const struct glue_vhdl_cb *callbacks, int level, const char *path_name, char c ) { bool log_start = true; const char *severity; switch (level) { case -1: log_start = false; break; case 0: severity = "NOTE"; break; case 1: severity = "WARNING"; break; case 2: severity = "ERROR"; break; case 3: severity = "FAILURE"; break; default: callbacks->log(FAUHDLI_LOG_ERROR, "fauhdli", __func__, "Illegal severity level %d\n", level); severity = "NOTE"; break; } if (log_start) { log_begin(callbacks, severity, path_name); } fprintf(stdout, "%c", c); if (c == '\n') { int ret = fflush(stdout); assert(ret == 0); } } fauhdlc-20130704/interpreter/trace.h0000664000175000017500000000425211343747723016632 0ustar potyrapotyra/* $Id: trace.h 4924 2010-03-04 15:20:51Z potyra $ * * Tracing related functionality. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TRACE_H_INCLUDED #define __TRACE_H_INCLUDED #include "fauhdli_private.h" #include "signals.h" #include #include struct trace_t { /* pointer to output file */ FILE *output; /** set of traced signals (uses internal tracing structure) */ struct slist *traced_sigs; /** next ident code to be handed out. */ char ident_code; /** header already written? */ bool header_written; }; /** create a trace instance. * @param trace_file output file name * @param callbacks that must have a log callback registered. * @return trace instance. */ extern struct trace_t * trace_create( const char *trace_file, const struct glue_vhdl_cb *callbacks ); /** destroy the trace instance. * @param s trace instance. */ extern void trace_destroy(struct trace_t *s, const struct glue_vhdl_cb *callbacks); /** add a signal to the set of traced signals. * @param s trace instance. * @param sigptr pointer to signal instance to trace. * @param name name of the signal * @param type basic type of the signal. * @param display_bits override display bits with this. (-1 means do not * override) * @param display_type vhdl base type, which can override values being * presented. * @param callbacks callbacks that must have a log callback registered. * @param array_size number of array elements */ extern void trace_add_signal( struct trace_t *s, const union fauhdli_value *sigptr, const char *name, enum type_kind type, int display_bits, const char *display_type, const struct glue_vhdl_cb *callbacks, int array_size ); /** Tell the tracer to advance the simulation time. * @param s trace instance. * @param sim_time new value of the simulation time. */ extern void trace_time_advance(struct trace_t *s, universal_integer sim_time); #endif /* __TRACE_H_INCLUDED */ fauhdlc-20130704/interpreter/glue/0000775000175000017500000000000012165333077016310 5ustar potyrapotyrafauhdlc-20130704/interpreter/glue/glue-main.c0000664000175000017500000000512011260622357020325 0ustar potyrapotyra/* $Id: glue-main.c 4775 2009-09-30 09:29:19Z potyra $ * Tiny reimplementation of time_virt() and time_call_at() * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "glue-main.h" #include #include #include #include static int failure = 0; static unsigned long long simulation_time = 0; static bool terminate = false; static struct { unsigned int n_calls; struct { void (*func)(void *data); void *data; unsigned long long tsc; } calls[10]; } time_calls; unsigned long long fauhdli_time_virt(void) { return simulation_time; } void fauhdli_time_call_at(unsigned long long tsc, void (*func)(void *data), void *data) { assert(time_calls.n_calls < 10); time_calls.calls[time_calls.n_calls].func = func; time_calls.calls[time_calls.n_calls].data = data; time_calls.calls[time_calls.n_calls].tsc = tsc; time_calls.n_calls++; } int fauhdli_time_call_delete(void (*func)(void *), void *data) { unsigned int i; for (i = 0; i < time_calls.n_calls; i++) { if (data == time_calls.calls[i].data) { size_t rs = sizeof(time_calls.calls) / sizeof(time_calls.calls[0]) - i - 1; if (rs == 0) { return 0; } memmove(&time_calls.calls[i], &time_calls.calls[i + 1], rs * sizeof(time_calls.calls[0])); return 0; } } return 1; } /** enter the main event loop. * May not be called anywhere in the library, as it's not part of * the standard glue-main. * -> only useful in interpreter.c which ships it's own "main" */ int fauhdli_main_event_loop(void) { while (! terminate) { unsigned int i; int entry = -1; unsigned long long min_time = INT64_MAX; if (time_calls.n_calls == 0) { break; } for (i = 0; i < time_calls.n_calls; i++) { if (time_calls.calls[i].tsc <= min_time) { min_time = time_calls.calls[i].tsc; entry = i; } } assert(entry != -1); simulation_time = min_time; time_calls.calls[entry].func(time_calls.calls[entry].data); /* remove entry from queue */ for (i = entry + 1; i < time_calls.n_calls; i++) { time_calls.calls[i - 1].func = time_calls.calls[i].func; time_calls.calls[i - 1].data = time_calls.calls[i].data; time_calls.calls[i - 1].tsc = time_calls.calls[i].tsc; } time_calls.n_calls--; } return failure; } void fauhdli_simulation_quit(int status) { terminate = true; failure = status; } fauhdlc-20130704/interpreter/glue/glue-log.c0000664000175000017500000000311111260435001020144 0ustar potyrapotyra/* $Id: glue-log.c 4773 2009-09-29 16:46:57Z potyra $ * * FAUmachine logging facility. * * Copyright (C) 2005-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ /* enable printing of timestamps if set to 1 */ #define LOG_TIMESTAMP 0 #include #include #include #include #if LOG_TIMESTAMP == 1 #include #endif #include "glue-log.h" void fauhdli_log( enum fauhdli_log_level level, const char *type, const char *name, const char *fmt, ... ) { va_list args; char buffer[1024]; char *buf = buffer; #if LOG_TIMESTAMP == 1 time_t t; struct tm *lt; size_t ret; t = time(NULL); lt = localtime(&t); assert(lt != NULL); ret = strftime(buf, sizeof(buffer), "%H:%M> ", lt); buf += ret; #endif switch (level) { case FAUHDLI_LOG_FATAL: strcpy(buf, "FATAL:"); break; case FAUHDLI_LOG_CRITICAL: strcpy(buf, "CRITICAL:"); break; case FAUHDLI_LOG_ERROR: strcpy(buf, "ERROR:"); break; case FAUHDLI_LOG_WARNING: strcpy(buf, "WARNING:"); break; case FAUHDLI_LOG_INFO: strcpy(buf, "INFO:"); break; case FAUHDLI_LOG_DEBUG: strcpy(buf, "DEBUG:"); break; default: assert(0); } strcat(buf, " "); strcat(buf, type); if (name[0] != '\0') { strcat(buf, " "); strcat(buf, name); } strcat(buf, ": "); va_start(args, fmt); vsprintf(buf + strlen(buf), fmt, args); va_end(args); fputs(buffer, stderr); } #undef LOG_TIMESTAMP fauhdlc-20130704/interpreter/glue/glue-vhdl.c0000664000175000017500000001510711352365516020347 0ustar potyrapotyra/* $Id: glue-vhdl.c 4928 2010-03-24 10:37:02Z potyra $ * * Glue layer between fauhdli and FAUmachine to access FAUmachine signals * from VHDL. * This file is only used for the standalone fauhdli interpreter, and * does nothing but log a few error messages. * Since the standalone interpreter uses free/malloc from glibc, it's * safe to use these here as well. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "glue-vhdl.h" #include "glue-log.h" #include #include struct glue_vhdl { unsigned int max_sig_id; unsigned int max_comp_id; unsigned int max_arch_id; }; void glue_vhdl_proc_set( void *_cpssp, const char *proc, const char *param, union fauhdli_value value ) { fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Set foreign parameter %s of procedure %s. Skipping.\n", param, proc); } void glue_vhdl_proc_call(void *_cpssp, const char *proc) { fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Foreign procedure call of %s requested. Skipping.\n", proc); } void glue_vhdl_set( void *_cpssp, unsigned int sig_id, union fauhdli_value data, void *drv ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(sig_id <= cpssp->max_sig_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Setting foreign signal %d requested. Skipping.\n", sig_id); } void glue_vhdl_connect_out( void *_cpssp, unsigned int sig_id, union fauhdli_value init, void *drv ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(sig_id <= cpssp->max_sig_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Connecting a driver to a foreign signal %d requested. " "Skipping.\n", sig_id); } void glue_vhdl_connect_in( void *_cpssp, unsigned int sig_id, void *drv ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(sig_id <= cpssp->max_sig_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Connecting a signal to a foreign signal %d requested. " "Skipping.\n", sig_id); } unsigned int glue_vhdl_create_signal( void *_cpssp, const char *type, const char *name ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Foreign signal %s of type %s requested. Skipping.\n", name, type); cpssp->max_sig_id++; return cpssp->max_sig_id; } unsigned int glue_vhdl_comp_create( void *_cpssp, const char *type, const char *name ) { struct glue_vhdl *cpssp = (struct glue_vhdl*)_cpssp; fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Foreign component %s of type %s requested. Skipping\n", name, type); cpssp->max_comp_id++; return cpssp->max_comp_id; } unsigned int glue_vhdl_arch_create( void *_cpssp, const char *type, const char *name ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Foreign architecture %s of type %s requested. Skipping\n", name, type); cpssp->max_arch_id++; return cpssp->max_arch_id; } void glue_vhdl_comp_init(void *_cpssp, unsigned int comp) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(comp <= cpssp->max_comp_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Initialization of foreign component %d requested." "Skipping.\n", comp); } void glue_vhdl_arch_init(void *_cpssp, unsigned int arch) { struct glue_vhdl *cpssp = (struct glue_vhdl*)_cpssp; assert(arch <= cpssp->max_comp_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Initialization of foreign architecture %d requested." "Skipping.\n", arch); } void glue_vhdl_comp_port_connect( void *_cpssp, unsigned int comp, const char *port, unsigned int sig ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(cpssp != NULL); assert(comp <= cpssp->max_comp_id); assert(sig <= cpssp->max_sig_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Foreign port %s of component %d request to connect to " "signal %d. Skipping\n", port, comp, sig); } void glue_vhdl_arch_port_connect( void *_cpssp, unsigned int arch, const char *port, unsigned int sig ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(cpssp != NULL); assert(arch <= cpssp->max_arch_id); assert(sig <= cpssp->max_sig_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Foreign port %s of architecture %d request to connect to " "signal %d. Skipping\n", port, arch, sig); } void glue_vhdl_comp_generic_nonarray_set( void *_cpssp, unsigned int comp, const char *generic, union fauhdli_value val, const char *type ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(cpssp != NULL); assert(comp <= cpssp->max_comp_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Setting foreign generic %s of component %d requested. " "Skipping.\n", generic, comp); } void glue_vhdl_arch_generic_nonarray_set( void *_cpssp, unsigned int arch, const char *generic, union fauhdli_value val, const char *type ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(cpssp != NULL); assert(arch <= cpssp->max_arch_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Setting foreign generic %s of architecture %d requested. " "Skipping.\n", generic, arch); } void glue_vhdl_comp_generic_array_set( void *_cpssp, unsigned int comp, const char *generic, const char *element_type, union fauhdli_value base, universal_integer array_size ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(cpssp != NULL); assert(comp <= cpssp->max_comp_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Setting foreign generic %s of component %d requested. " "Skipping.\n", generic, comp); } void glue_vhdl_arch_generic_array_set( void *_cpssp, unsigned int arch, const char *generic, const char *element_type, union fauhdli_value base, universal_integer array_size ) { struct glue_vhdl *cpssp = (struct glue_vhdl *)_cpssp; assert(cpssp != NULL); assert(arch <= cpssp->max_arch_id); fauhdli_log(FAUHDLI_LOG_WARNING, "fauhdli", "glue-vhdl", "Setting foreign generic %s of architecture %d requested. " "Skipping.\n", generic, arch); } void * glue_vhdl_create(void) { struct glue_vhdl *ret = malloc(sizeof(struct glue_vhdl)); ret->max_sig_id = 0; ret->max_comp_id = 0; ret->max_arch_id = 0; return ret; } void glue_vhdl_destroy(void *_cpssp) { assert(_cpssp != NULL); free(_cpssp); } fauhdlc-20130704/interpreter/glue/glue-main.h0000664000175000017500000000303311260622357020333 0ustar potyrapotyra/* $Id: glue-main.h 4775 2009-09-30 09:29:19Z potyra $ * FAUmachine main simulation functionality (stripped to necessary parts) * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GLUE_MAIN_H_INCLUDED #define __GLUE_MAIN_H_INCLUDED #include /** Get virtual time. * @return virtual time in TIME_HZ ticks. */ extern unsigned long long fauhdli_time_virt(void); /** Register a timer to call func with parameter data as soon as the * simulation time tsc is reached. * @param tsc virtual timestamp counter, 1 second == 1 * TIME_HZ. * @param func callback that will be called. * @param data parameter to the callback. */ extern void fauhdli_time_call_at(unsigned long long tsc, void (*func)(void *data), void *data); /** delete a registered timer from time_call_at. * @param func callback that would have been called. * @param data data that would have been the argument (must match * data from time_call_at/time_call_after). * @return 0 for success, 1 if the timer was not found. */ extern int fauhdli_time_call_delete(void (*func)(void *), void *data); /** Stop simulation node. */ extern void fauhdli_simulation_quit(int status); /** execute the main event loop * @return exit status. */ extern int fauhdli_main_event_loop(void); #endif /* __GLUE_MAIN_H_INCLUDED */ fauhdlc-20130704/interpreter/glue/glue-vhdl.h0000664000175000017500000001701411260411744020344 0ustar potyrapotyra/* $Id: glue-vhdl.h 4769 2009-09-29 14:04:20Z potyra $ * * Glue layer between fauhdli and FAUmachine to access FAUmachine signals * from VHDL. This is the local implementation for a standalone * fauhdli interpreter. (Most callbacks simply print an info). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GLUE_VHDL_H_INCLUDED #define __GLUE_VHDL_H_INCLUDED #include "fauhdli.h" extern void * glue_vhdl_create(void); extern void glue_vhdl_destroy(void *_cpssp); /** Create a foreign component (entity). * @param _cpssp glue_vhdl instance. * @param type type of the component (entity name). * @param name name of the instantiated unit * @return unique component id. */ extern unsigned int glue_vhdl_comp_create( void *_cpssp, const char *type, const char *name ); /* Create a FAUmachine signal and return its ID. * @param _cpssp opaque pointer. * @param type type of the signal. * @param name signal name (for debugging only) * @return unique signal id. */ extern unsigned int glue_vhdl_create_signal( void *_cpssp, const char *type, const char *name ); /** Initialize a foreign architecture. * The foreign architecture must first have been created with * glue_vhdl_arch_create and the ports must have been connected * with glue_vhdl_arch_port_connect (same with generics). * * @param _cpssp glue_vhdl instance. * @param arch architecture id (cf. glue_vhdl_arch_create). */ extern void glue_vhdl_arch_init(void *_cpssp, unsigned int arch); /** set a FAUmachine signal with signal id sig_id and data data. * @param _cpssp opaque pointer. * @param sig_id signal id (cf. system.h) * @param data data fitting to the signal. (FIXME composites) * @param drv pointer to driver instance. */ extern void glue_vhdl_set( void *_cpssp, unsigned int sig_id, union fauhdli_value data, void *drv ); /** Set a procedure call argument of a foreign procedure. * @param _cpssp opaque pointer. * @param proc name of the foreign procedure. * @param param name of the parameter * @param value parameter value. Content depending on the signature * of the foreign procedure. * For parameter passing mechanisms, see GenCode.cpp. */ extern void glue_vhdl_proc_set( void *_cpssp, const char *proc, const char *param, union fauhdli_value value ); /** Call a foreign procedure. * @param _cpssp opaque pointer. * @param proc name of the procedure to call. */ extern void glue_vhdl_proc_call(void *_cpssp, const char *proc); /** Create a foreign architecture. A foreign architecture means, that * it is really declared in VHDL, but could e.g. instantiate only * foreign entities. This is mainly a callback before the VHDL * architecture gets created (but after the signals for the architecture * have been created), in case of need. * * @param _cpssp opaque pointer. * @param type type of the component (entity name). * @param name name of the instantiated architecture * @return unique component id. */ extern unsigned int glue_vhdl_arch_create( void *_cpssp, const char *type, const char *name ); /** Connect a VHDL signal to a FAUmachine signal so that writes are getting * forwarded to FAUmachine. * This function should get called if a VHDL driver is connected to a * foreign VHDL signal. * @param _cpssp opaque pointer. * @param sig_id FAUmachine signal id. * @param init initial driving value. * @param drv corresponding driver pointer. */ extern void glue_vhdl_connect_out( void *_cpssp, unsigned int sig_id, union fauhdli_value init, void *drv ); /** Connect a foreign signal that is read from VHDL. * This function will call drv_update or in case a FAUmachine signal with * sig_id obtains a new value. * @param _cpssp opaque pointer. * @param sig_id unique FAUmachine signal id. * @param drv driver instance that will be passed as _drv parameter for * drv_update */ extern void glue_vhdl_connect_in( void *_cpssp, unsigned int sig_id, void *drv ); /** Initialize a foreign component. * The foreign component must first have been created with * glue_vhdl_comp_create and the ports must have been connected * with glue_vhdl_comp_port_connect. * * @param _cpssp opaque pointer. * @param comp component id (cf. glue_vhdl_comp_create). */ extern void glue_vhdl_comp_init(void *_cpssp, unsigned int comp); /** connect a foreign signal to the port of a foreign component. * @param _cpssp opaque pointer. * @param comp unique component id (cf. glue_vhdl_comp_create, return value) * @param port name of the desired port. * @param sig unique signal id (cf. glue_vhdl_create_signal, return value) */ extern void glue_vhdl_comp_port_connect( void *_cpssp, unsigned int comp, const char *port, unsigned int sig ); /** connect a foreign signal to the port of a foreign component. * @param _cpssp opaque pointer. * @param arch unique architecture id (cf. glue_vhdl_arch_create, * return value) * @param port name of the desired port. * @param sig unique signal id (cf. glue_vhdl_create_signal, return value) */ extern void glue_vhdl_arch_port_connect( void *_cpssp, unsigned int arch, const char *port, unsigned int sig ); /** set a generic of a foreign component (which is not an array). * @param _cpssp opaque pointer. * @param comp unique component id (cf. glue_vhdl_comp_create, return value) * @param generic name of the desired generic. * @param val VHDL value (direct value for non-composites, pointer for * record types). * @param type name of the corresponding VHDL type. */ extern void glue_vhdl_comp_generic_nonarray_set( void *_cpssp, unsigned int comp, const char *generic, union fauhdli_value val, const char *type ); /** set a generic of a foreign architecture (which is not an array). * @param _cpssp opaque pointer. * @param comp unique component id (cf. glue_vhdl_comp_create, return value) * @param generic name of the desired generic. * @param val VHDL value (direct value for non-composites, pointer for * record types). * @param type name of the corresponding VHDL type. */ extern void glue_vhdl_arch_generic_nonarray_set( void *_cpssp, unsigned int arch, const char *generic, union fauhdli_value val, const char *type ); /** set a generic of a foreign component (which is an array). * @param _cpssp opaque pointer. * @param comp unique component id (cf. glue_vhdl_comp_create, return value) * @param generic name of the desired generic. * @param element_type type name of the element type * @param base pointer to base of array. * @param array_size size of array. */ extern void glue_vhdl_comp_generic_array_set( void *_cpssp, unsigned int comp, const char *generic, const char *element_type, union fauhdli_value base, universal_integer array_size ); /** set a generic of a foreign architecture (which is an array). * @param _cpssp opaque pointer. * @param arch unique architecture id (cf. glue_vhdl_comp_create, * return value) * @param generic name of the desired generic. * @param element_type type name of the element type * @param base pointer to base of array. * @param array_size size of array. */ extern void glue_vhdl_arch_generic_array_set( void *_cpssp, unsigned int arch, const char *generic, const char *element_type, union fauhdli_value base, universal_integer array_size ); #endif /* __GLUE_VHDL_H_INCLUDED */ fauhdlc-20130704/interpreter/glue/glue-log.h0000664000175000017500000000235111260435001020156 0ustar potyrapotyra/* $Id: glue-log.h 4773 2009-09-29 16:46:57Z potyra $ * * FAUmachine logging facility. * * Copyright (C) 2005-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GLUE_LOG_H_INCLUDED #define __GLUE_LOG_H_INCLUDED /* * DEBUG: should only be shown if debugging is enabled * INFO: all information that is useful to the *user* * WARNING: if something is not being simulated correctly, but * should continue working without problems * ERROR: if something definitely went wrong, but the component * continues working * CRITICAL: if something went wrong and the component * is not supposed to continue working correctly * FATAL: if the component does not know what to do */ enum fauhdli_log_level { FAUHDLI_LOG_FATAL, FAUHDLI_LOG_CRITICAL, FAUHDLI_LOG_ERROR, FAUHDLI_LOG_WARNING, FAUHDLI_LOG_INFO, FAUHDLI_LOG_DEBUG, }; extern void fauhdli_log(enum fauhdli_log_level level, const char *type, const char *name, const char *fmt, ...) __attribute__ ((format (printf, 4, 5))); #endif /* __GLUE_LOG_H_INCLUDED */ fauhdlc-20130704/interpreter/fauhdli_private.h0000664000175000017500000002322111457100074020663 0ustar potyrapotyra/* $Id: fauhdli_private.h 4975 2010-10-18 17:13:32Z potyra $ * Interpreter library, internal API. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FAUHDLI_PRIVATE_H_INCLUDED #define __FAUHDLI_PRIVATE_H_INCLUDED #include "fauhdli.h" #include #include /* for size_t */ #include "list.h" #include "slset.h" #include "vhdl_sched.h" #include "basetypes.h" /* ********************* types *********************** */ enum opcode_kind { OPCODE_MOV, /* 0 */ OPCODE_ADD, OPCODE_SUB, OPCODE_IMUL, OPCODE_DIV, OPCODE_CALL, /* 5 */ OPCODE_PROC, OPCODE_RETURN, OPCODE_BEGINTRANS, OPCODE_ENDTRANS, OPCODE_SETPARAM, /* 10 */ OPCODE_GETPARAM, OPCODE_UPDATE, OPCODE_GETSIG, OPCODE_JMP, OPCODE_JE, /* 15 */ OPCODE_JB, OPCODE_JNE, OPCODE_JBE, OPCODE_AOFFSET, OPCODE_ROFFSET, /* 20 */ OPCODE_LABEL, OPCODE_SUSPEND, OPCODE_CONNECT, OPCODE_WAKEAT, OPCODE_WAKEON, /* 25 */ OPCODE_LOG, OPCODE_ABORT, OPCODE_GETSIMTIME }; /** kind of operand */ enum operand_kind { /** register operand */ OPERAND_REGISTER, /** indirect memory access via register */ OPERAND_INDIRECT, /** immediate operand */ OPERAND_IMMEDIATE, /** reference to a data object. (= pointer to data) */ OPERAND_REFERENCE, /** reference to a label */ OPERAND_TARGET }; /** basic type enumeration */ enum type_kind { /** integral type */ TYPE_INT, /** float type */ TYPE_FLOAT, /** pointer type */ TYPE_POINTER, }; /** storage kinds of data elements */ enum storage_kind { /** plain storage, only the value is stored. */ STORAGE_VARIABLE, /** signal storage, defining a signal */ STORAGE_SIGNAL, /** driver storage, a driver to a signal */ STORAGE_DRIVER }; /** code container */ struct code_container { /** name of the container */ char *name; /** list of types */ struct slist *type_definitions; /** architecture segment */ struct slist *transfer_segment; /** stack segment */ struct slist *stack_segment; /** nested code containers */ struct slist *sub_containers; /** data size of stack segment */ size_t stack_size; /** data size of transfer segment */ size_t transfer_size; /** text segment */ struct slist *text_segment; /** nesting level of container */ unsigned int nesting_level; /** number of used virtual registers by code_container */ unsigned int num_vregs; }; /** one intermediate code operand */ struct operand { /** kind of operand */ enum operand_kind kind; /** type of operand */ enum type_kind type; /** union by kind of operand */ union { /** register for register and indirect operands */ unsigned int reg; /** immediate value */ union fauhdli_value immediate; /** reference to a label */ struct { /** name of the label */ char *name; /** resolved reference or NULL if unresolved */ const struct slist_entry *ref; } target; /** reference to a data object, or a code container */ struct { /** name of the reference */ char *name; /** resolved reference or NULL if unresolved */ const struct data_definition *ref; /** for setparam, begintrans, endtrans: * reference to the code container */ const struct code_container *container; } data; } bytype; }; struct opcode { /** kind of opcode */ enum opcode_kind kind; /** first operand (if any) */ struct operand *op1; /** second operand (if any) */ struct operand *op2; /** third operand (if any) */ struct operand *op3; /** label, in case it's no opcode but a label. */ char *label; /** type element referring to the indexed type in caes of * aoffset/roffset opcodes */ struct type_element *indexed_type; /** line number in parsed file */ int lineno; /** list of annotations (optional) */ struct slist *annotations; }; /** generic annotation specification */ struct annotation_spec { /** name of the annotation specification */ char *name; /** string value */ char *string_value; /** int value */ int int_value; }; /** Element of a type. * * A type_element represents one element of a possibly composite type. * It can represent an array of either a basic type or another composite * type. * A basic type would be universal_integer or universal_real, or a driver * of it, or a signal of it. * * elem_count represents the number of basic types that this type_element * refers to. * offset means the number of basic type elements in a composite type * that reside before this type. * * Example: * type t is { a: u[10], b: v } * type u is { c: universal_integer[5] } * type v is { d: universal_real, e: universal_integer } * * type_element d has offset 0 and elem_count 1 * type_element e has offset 1 and elem_count 1 * type v has elem_count 2 * * type_element c has offset 0 and elem_count 5 * type u has elem_count 5 * * type_elment a has offset 0 and elem_count 10 * 5 = 50 (and elements = 10) * type_element b has offset 50 and elem_count 2 (and elements = 1) * type t has elem_count 52 */ struct type_element { /** name of the referred to type */ char *name; /** referred to type */ const struct type_declaration *type; /** number of elements of an array */ universal_integer elements; /** list of initial values */ struct slist *initial_list; /** number of basic subelements. -1 means unset. */ int elem_count; /** element offset from beginning of type (not a size!) */ int offset; /** annotations (optional) */ struct slist *annotations; }; struct type_declaration { /** name of the type */ char *name; /** subelements of the type */ struct slist *elements; /** number of basic subelements. -1 means unset. */ int elem_count; }; enum segment_kind { SEGMENT_TRANSFER, SEGMENT_STACK }; struct data_definition { /** name of the definition */ char *name; /** type of the definition (local type_element) */ struct type_element *type; /** storage kind of the data definition */ enum storage_kind storage; /** location of the data. */ enum segment_kind loc; /** nesting level, 0=current stack seg., 1=parent stack seg..) */ unsigned int nesting_level; /** offset of data in segment (bytes) */ size_t offset; /** storage size in byte of the resulting data */ size_t storage_size; /** annotations (optional) */ struct slist *annotations; /** reference to a resolution function */ struct { /** name of resolution function */ char *name; /** container of the resolution function */ const struct code_container *container; } resolver; }; /** value of a virtual register */ struct reg_value { /** actual value */ union fauhdli_value value; /** type of register (mainly useful for debugging */ enum type_kind kind; /** was the register written to already? * (only useful to debug intermediate code) */ bool initialized; }; /** foreign mode for port/generic SetParams. */ enum foreign_mode_e { /** component instantiation mode */ FOREIGN_MODE_COMPONENT, /** architecture create mode */ FOREIGN_MODE_ARCHITECTURE }; /** main instance of vhdl interpreter */ struct fauhdli { /** top code container. */ struct code_container *container; /** set containing various allocated pointers that should get free'd * on exit. (order must not be relevant!) */ struct slset *cleanup_ptrs; /** scheduler instance */ struct vhdl_sched *scheduler; /** set of created signals */ struct slset *signals; /** set of created, but not free'd stack_frames */ struct slset *pending_stack_frames; /** all vhdl processes */ struct slset *processes; /** current simulation time */ universal_integer sim_time; /** tracer instance (NULL if no tracing is desired) */ struct trace_t *tracer; /** debugging enabled/disabled? */ bool debug; /** opaque glue_vhdl pointer. */ void *glue_vhdl; /** set containing all (non-foreign) drivers */ struct slset *drivers; /** set of all "foreign" drivers. A foreign driver means that the * signal of a process is written to from VHDL but the signal itself * is foreign. */ struct slset *foreign_drivers; /** helper structure for setting foreign generics of arrays */ struct { /** component id */ unsigned int comp_id; /** pointer to base (NULL means not yet set) */ union fauhdli_value base; /** name of generic (formal name) */ const char *formal_name; /** element type name */ const char *element_type; /** left bound */ universal_integer left; /** left bound set */ bool left_set; /** right bound */ universal_integer right; /** right bound set */ bool right_set; /** direction */ universal_integer direction; /** direction set? */ bool direction_set; } foreign_g_array_params; /** mode for foreign generics/ports */ enum foreign_mode_e foreign_mode; /** callbacks for foreign interface. */ struct glue_vhdl_cb callbacks; /** wakeup event already scheduled? */ bool wakeup_scheduled; /** list of entities to trace */ struct slist *trace_list; }; /* ********************* functions *********************** */ /** allocate memory for an opcode an initialize the members. * @param kind kind of opcode. * @param callbacks for malloc * @return opcode with kind set, and pointers set to 0. */ extern __attribute__((__malloc__)) struct opcode * fauhdli_alloc_opcode( enum opcode_kind kind, const struct glue_vhdl_cb *callbacks ); /** find the annotation with name in the list of annotations. * @param name name tag of the annotation * @param annotations list of annotations * @return the spec in question or NULL if not found. */ extern const struct annotation_spec * fauhdli_find_annotation(const char *name, const struct slist *annotations); #endif /* __FAUHDLI_PRIVATE_H_INCLUDED */ fauhdlc-20130704/interpreter/fauhdli.h0000664000175000017500000002722211260675634017151 0ustar potyrapotyra/* $Id: fauhdli.h 4778 2009-09-30 15:39:08Z potyra $ * Interpreter library. External API * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FAUHDLI_H_INCLUDED #define __FAUHDLI_H_INCLUDED #include #include #include /** forward declaration of struct fauhdli, which is opaque to external * users. */ struct fauhdli; /** any directly used VHDL value. */ union fauhdli_value { /** integer value */ universal_integer univ_int; /** real value */ universal_real univ_real; /** pointer value */ void *pointer; }; /** Callbacks for foreign interface. */ struct glue_vhdl_cb { /* --------------- memory management ------------ */ /** allocate memory (optional, fallback: malloc). * @param size number of bytes to allocate. * @return pointer to allocated memory (or NULL on error). */ void *(*malloc)(size_t size); /** free allocated memory again (optional, fallback: free). * @param ptr pointer to allocated chunk. */ void (*free)(void *ptr); /* ------------------ scheduling --------------- */ /* for the scheduling callbacks, either all must be set, or * None may be set, resulting in the builtin implementation. */ /** Get virtual time. * @return virtual time. */ unsigned long long (*time_virt)(void); /** Register a timer to call func with parameter data as soon as the * simulation time tsc is reached. * @param tsc virtual timestamp counter, 1 second == 1 * TIME_HZ. * @param func callback that will be called. * @param data parameter to the callback. */ void (*time_call_at)( unsigned long long tsc, void (*func)(void *data), void *data); /** Delete a registered timer from time_call_at. * @param func callback that would have been called. * @param data data that would have been the argument (must match * data from time_call_at/time_call_after). * @return 0 for success, 1 if the timer was not found. */ int (*time_call_delete)(void (*func)(void *), void *data); /** Tell the scheduler to quit the simulation. * @param status: 0=success, others=error. */ void (*quit)(int status); /* ------------------- logging ----------------- */ /** Log an interpreter error message. Optional, fallback: builtin * implementation. * @param level severity of error (0=fatal, 1=critical, 2=error, * 3=warning, 4=info, 5=debug) * @param type submodule from which the error comes. * @param name name of the module/function that throws the error. * @param fmt format string. */ void (*log)( int level, const char *type, const char *name, const char *fmt, ...); /** Create a foreign component (entity). * @param _cpssp opaque pointer. * @param type type of the component (entity name). * @param name name of the instantiated unit * @return unique component id. */ unsigned int (*comp_create)( void *_cpssp, const char *type, const char *name); /** Initialize a foreign component. * The foreign component must first have been created with * comp_create and the ports must have been connected * with comp_port_connect. * * @param _cpssp opaque pointer. * @param comp component id (cf. glue_vhdl_comp_create). */ void (*comp_init)(void *_cpssp, unsigned int comp_id); /* Create a foreign signal and return its ID. * @param _cpssp opaque pointer. * @param type type of the signal. * @param name signal name (for debugging only) * @return unique signal id. */ unsigned int (*signal_create)( void *_cpssp, const char *type, const char *name); /** connect a foreign signal to the port of a foreign component. * @param _cpssp opaque pointer. * @param comp unique component id (cf. comp_create, return value) * @param port name of the desired port. * @param sig unique signal id (cf. signal_create, return value) */ void (*comp_port_connect)( void *_cpssp, unsigned int comp, const char *port, unsigned int sig); /** Create a foreign architecture. A foreign architecture means, that * it is really declared in VHDL, but could e.g. instantiate only * foreign entities. This is mainly a callback before the VHDL * architecture gets created (but after the signals for the * architecture have been created), in case of need. * * @param _cpssp opaque pointer. * @param type type of the component (entity name). * @param name name of the instantiated architecture * @return unique architecture id. */ unsigned int (*arch_create)( void *_cpssp, const char *type, const char *name); /** Initialize a foreign architecture. * The foreign architecture must first have been created with * glue_vhdl_arch_create and the ports must have been connected * with glue_vhdl_arch_port_connect (same with generics). * * @param _cpssp opaque pointer. * @param arch architecture id (cf. arch_create). */ void (*arch_init)(void *_cpssp, unsigned int arch); /** connect a foreign signal to the port of a foreign component. * @param _cpssp opaque pointer * @param arch unique architecture id (cf. glue_vhdl_arch_create, * return value) * @param port name of the desired port. * @param sig unique signal id (cf. glue_vhdl_create_signal, return * value) */ void (*arch_port_connect)( void *_cpssp, unsigned int arch, const char *port, unsigned int sig); /** Set the value of a foreign driver. * @param _cpssp opaque pointer. * @param sig_id signal id. * @param data data fitting to the signal. (FIXME composites). * @param drv pointer to VHDL driver (cf. connect_out, this * pointer can be used to identify a driver. It mustn't * be modified nor may any assumptions be made about the * data stored at the driver.) */ void (*drv_set)( void *_cpssp, unsigned int sig_id, union fauhdli_value data, void *drv); /** Connect a VHDL signal to a foreign signal so that writes are * getting forwarded to the foreign interface. * This function gets called if a VHDL driver is connected to a * foreign VHDL signal. * @param _cpssp opaque pointer. * @param sig_id foreign signal id. * @param init initial driving value. * @param drv corresponding driver pointer. */ void (*connect_out)( void *_cpssp, unsigned int sig_id, union fauhdli_value init, void *drv); /** Connect a foreign signal that is read from VHDL. * Register a foreign signal, that is read from VHDL. Whenever the * foreign signal recieves a new value, it should call * fauhdli_foreign_drv_update. * @param _cpssp opaque pointer. * @param sig_id unique foreign signal id. * @param drv driver instance that will be passed as _drv parameter * for fauhdli_foreign_drv_update. */ void (*connect_in)( void *_cpssp, unsigned int sig_id, void *drv); /** set a generic of a foreign component (which is not an array). * @param _cpssp opaque pointer. * @param comp unique component id (cf. comp_create, return value) * @param generic name of the desired generic. * @param val VHDL value (direct value for non-composites, * pointer for record types). * @param type name of the corresponding VHDL type. */ void (*comp_generic_nonarray_set)( void *_cpssp, unsigned int comp, const char *generic, union fauhdli_value val, const char *type); /** set a generic of a foreign component (which is an array). * @param _cpssp opaque pointer. * @param comp unique component id (cf. glue_vhdl_comp_create, * return value) * @param generic name of the desired generic. * @param element_type type name of the element type * @param base pointer to base of array. * @param array_size size of array. */ void (*comp_generic_array_set)( void *_cpssp, unsigned int comp, const char *generic, const char *element_type, union fauhdli_value base, universal_integer array_size); /** set a generic of a foreign architecture (which is not an array). * @param _cpssp opaque pointer. * @param comp unique component id (cf. glue_vhdl_comp_create, * return value) * @param generic name of the desired generic. * @param val VHDL value (direct value for non-composites, pointer * for record types). * @param type name of the corresponding VHDL type. */ void (*arch_generic_nonarray_set)( void *_cpssp, unsigned int arch, const char *generic, union fauhdli_value val, const char *type); /** set a generic of a foreign architecture (which is an array). * @param _cpssp opaque pointer. * @param arch unique architecture id (cf. arch_create, * return value) * @param generic name of the desired generic. * @param element_type type name of the element type * @param base pointer to base of array. * @param array_size size of array. */ void (*arch_generic_array_set)( void *_cpssp, unsigned int arch, const char *generic, const char *element_type, union fauhdli_value base, universal_integer array_size); /** Set a procedure call argument of a foreign procedure. * @param _cpssp opaque pointer. * @param proc name of the foreign procedure. * @param param name of the parameter * @param value parameter value. Content depending on the signature * of the foreign procedure. * For parameter passing mechanisms, see GenCode.cpp. */ void (*proc_set)( void *_cpssp, const char *proc, const char *param, union fauhdli_value value); /** Call a foreign procedure. * @param _cpssp opaque pointer. * @param proc name of the procedure to call. */ void (*proc_call)(void *_cpssp, const char *proc); }; /** create the VHDL interpreter. * @param parse_file intermediate code file to parse. * @param trace_file name of vcd trace file (to trace signals of top_entity) * or NULL, if no output is desired. * @param debug debugging output enabled/disabled? * @param callbacks callbacks for foreign interface. * @param _cpssp opaque pointer that will get passed back to the callbacks. * @return fauhdli instance. */ extern __attribute__((visibility("default"))) struct fauhdli * fauhdli_create( const char *parse_file, const char *trace_file, bool debug, const struct glue_vhdl_cb *callbacks, void *_cpssp ); /** destroy the fauhdli instance. * @param instance fauhdli instance. */ extern void __attribute__((visibility("default"))) fauhdli_destroy(struct fauhdli *instance); /** initialize/run simulator * @param instance simulator instance. * @param top_entity start simulation with entity called like this. */ extern void __attribute__((visibility("default"))) fauhdli_init(struct fauhdli *instance, const char *top_entity); /** find out the foreign signal id for a signal * @param _sig pointer to signal instance. * @return foreign signal id */ extern __attribute__((visibility("default"))) unsigned int fauhdli_get_sig_id(const void *_sig); /** find out the foreign signal id for a driver * @param _drv pointer to driver instance. * @return foreign signal id */ extern __attribute__((visibility("default"))) unsigned int fauhdli_get_sig_id_driver(const void *_drv); /** Update the value of a driver. * @param instance fauhdli instance. * @param _drv pointer to the VHDL driver instance. * @param value updated value. */ extern void __attribute__((visibility("default"))) fauhdli_set_driver( struct fauhdli *instance, void *_drv, union fauhdli_value value ); #endif /* __FAUHDLI_H_INCLUDED */ fauhdlc-20130704/TODO0000664000175000017500000000230211162447601013471 0ustar potyrapotyra# $Id: TODO 4390 2009-03-25 15:36:33Z potyra $ Things not implemented yet: --------------------------- ========== = Parser = ========== * record aggregate assignments * much more, see FIXME/TODO comments ================= = Type analysis = ================= * needs code cleanup! * individual association * named association for function calls * implicit conversions and function calls (eliminates correct possibilities sometimes, e.g. "if 2 = x then"). ===================== = Semantic analysis = ===================== * check pure'ness of functions/procedures (impure is not always legal) * replace concurrent statements with processes * check select/case statements if all values are present * check procedure call statements writing to signals that are not passed as parameters, since this is only legal in subprograms of process statements (LRM 123). GatherImplicites: also pick up drivers from non-parameters of subprogram calls. * check if the actual of a formal of class variable is a variable. * handle subtype conversions for array constraints on assignment (and others). =================== = ICode generator = =================== * slice handling * mapping/annotating foreign composite types. fauhdlc-20130704/README.macosx0000664000175000017500000000046611142571437015166 0ustar potyrapotyra# $Id: README.macosx 4355 2009-02-05 14:09:35Z sand $ ============== = BUILD NOTE = ============== DO NOT try to build fauhdlc on Mac OS X with gc (general purpose garbage collecting storage allocator). It won't run! libgc is NOT essential; if it is not present, fauhdlc will build and run without it, too. fauhdlc-20130704/compiler/0000775000175000017500000000000012165333100014606 5ustar potyrapotyrafauhdlc-20130704/compiler/FAUhdlc.hpp0000664000175000017500000000623411456057656016617 0ustar potyrapotyra/* $Id: FAUhdlc.hpp 4947 2010-10-15 14:05:34Z potyra $ * * Copyright (C) 2007-2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FAUHDLC_HPP_INCLUDED #define __FAUHDLC_HPP_INCLUDED #include #include #include #include "frontend/ast/AstNode.hpp" #include "frontend/misc/SymbolTable.hpp" #include "intermediate/Node.hpp" namespace compiler { //! main compiler class. class FAUhdlc { public: //! c'tor FAUhdlc(); //! d'tor ~FAUhdlc(); //! parse the command line arguments /** @param argc number of command line arguments. * @param argv vector of command line arguments. */ void parseCmdLine(int argc, char **argv); //! compile. /** @return exit status */ int run(); private: /** possible error codes */ enum ResultCodes { FAUHDLC_EXIT_SUCCESS = 0, //!< everything ok. FAUHDLC_EXIT_COMMAND_ARGS = 1, //!< wrong command line args FAUHDLC_EXIT_ERROR = 3, //!< compile error was found FAUHDLC_EXIT_EXCEPTION = 4 //!< other Exception occured }; //! mapping class for filename to library name struct LibFile { std::string *filename; //!< full path to file. const char *library; //!< name of library in which file is. }; //! display command line usage. /** @param out stream on which usage should be put. */ void usage(std::ostream &out) const; //! parse a file void doParse(void); //! do the semantic analysis void doSemanticAnalysis(void); //! write out any warnings/errors void putCompileMessages(void); //! perform transformations on intermediate code /** currently, this will only write the intermediate code to * the output file, in case one was specified. * More to come. */ void doIntermediateTransform(void); //! print intermediate code to file. /** print intermediate code to file specified in * this->outfile. */ void printICode(void); //! generate C code from intermediate code /** generate C code from intermediate code and output * it to file specified in this->cFile. */ void genCCode(void); /** top AST node. */ ast::AstNode *topNode; /** stop after parsing */ bool parseOnly; /** generate dot file after parsing. */ bool dotParse; /** result code reported back to main */ enum ResultCodes resultCode; /** file that should get compiled */ std::list sourceFiles; /** filename of the dot file after parsing */ const char *dotParseFile; /** name of the output file */ const char *outputFile; /** symbol table used in first steps of semantic analysis */ ast::SymbolTable *symbolTable; /** intermediate code top node. */ intermediate::Node *iTopNode; /** create dot file after constant propagation? */ bool dotConst; /** filename of the dot file after constant propagation */ const char *dotConstFile; /** freestanding mode? (don't load common libraries like std_logic */ bool freeStanding; /** filename of C output file. */ const char *cFile; }; }; /* namespace compiler */ #endif /* __FAUHDLC_HPP_INCLUDED */ fauhdlc-20130704/compiler/FAUhdlc.cpp0000664000175000017500000003135111502674044016574 0ustar potyrapotyra/* $Id: FAUhdlc.cpp 5079 2010-12-17 14:48:04Z potyra $ * * FAUhdlc: main class to setup and execute compilation. * * Copyright (C) 2007-2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include extern "C" { #ifndef _GNU_SOURCE #define _GNU_SOURCE #include #undef _GNU_SOURCE #else /* _GNU_SOURCE not externally defined */ #include #endif /* _GNU_SOURCE externally defined */ }; #include "compiler/FAUhdlc.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/newparser/ParserDriver.hpp" #include "util/MiscUtil.hpp" #include "util/GarbageCollect.hpp" #include "frontend/visitor/DotVisitor.hpp" #include "frontend/misc/BuiltinSymbolTable.hpp" #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/visitor/SetPathName.hpp" #include "frontend/visitor/GatherImplicits.hpp" #include "frontend/visitor/GenCode.hpp" #include "frontend/visitor/ConstantPropagation.hpp" #include "frontend/visitor/CheckLoops.hpp" #include "frontend/visitor/CheckAccessMode.hpp" #include "frontend/visitor/NormalizeAssocLists.hpp" #include "frontend/visitor/WaitConditions.hpp" #include "frontend/visitor/WarnUnused.hpp" #include "frontend/visitor/TransformSigAssign.hpp" #include "intermediate/visitor/PrintCode.hpp" #include "intermediate/visitor/GenCCode.hpp" #include "intermediate/visitor/LookupSymbols.hpp" namespace compiler { FAUhdlc::FAUhdlc() : topNode(NULL), parseOnly(false), dotParse(false), resultCode(FAUHDLC_EXIT_SUCCESS), dotParseFile(NULL), outputFile(NULL), symbolTable(NULL), iTopNode(NULL), dotConst(false), dotConstFile(NULL), freeStanding(false), cFile(NULL) { } FAUhdlc::~FAUhdlc() { // cleanup memory (only useful for leak checking) for (std::list::iterator i = this->sourceFiles.begin(); i != this->sourceFiles.end(); i++) { delete (*i)->filename; delete *i; } util::MiscUtil::terminate(this->topNode); delete this->symbolTable; util::MiscUtil::terminate(this->iTopNode); } void FAUhdlc::parseCmdLine(int argc, char** argv) { const char *currentLib = "work"; bool success = true; bool again = true; int c; struct option l_opts[] = { /* name, has_arg, *flag, val */ {"parse-only", 0, NULL, 'p'}, {"dot-parse", 1, NULL, 'd'}, {"dot-const", 1, NULL, 'c'}, {"lib", 1, NULL, 'l'}, {"output", 1, NULL, 'o'}, {"c-output", 1, NULL, 'C'}, {"help", 0, NULL, 'h'}, {"freestanding", 0, NULL, 'f'}, {0, 0, 0, 0} }; while (again) { c = getopt_long(argc, argv, "-pd:c:l:o:hW:C:f", l_opts, NULL); switch (c) { case -1: /* no more options */ again = false; break; case 1: /* "non"-option, name of compile file */ { struct FAUhdlc::LibFile *f = new struct FAUhdlc::LibFile(); f->filename = new std::string(optarg); f->library = currentLib; this->sourceFiles.push_back(f); break; } case 'p': /* parse-only */ this->parseOnly = true; break; case 'd': /* dot-parse= */ this->dotParse = true; this->dotParseFile = optarg; break; case 'c': /* dot-const= */ this->dotConst = true; this->dotConstFile = optarg; break; case 'l': /* lib= */ currentLib = optarg; break; case 'o': /* output= */ this->outputFile = optarg; break; case 'h': /* help */ success = false; break; case 'W': /* warning options */ if (strcmp("error", optarg) == 0) { ast::ErrorRegistry::setWerror(true); } else { success = false; } break; case 'f': /* freestanding */ this->freeStanding = true; break; case 'C': /* C-Output */ this->cFile = optarg; break; }; } /** at least one file? */ if (this->sourceFiles.size() == 0) { success = false; } if (! success) { this->resultCode = FAUHDLC_EXIT_COMMAND_ARGS; this->usage(std::cerr); } } int FAUhdlc::run(void) { if (this->resultCode != FAUHDLC_EXIT_SUCCESS) { return this->resultCode; } this->doParse(); if ( (this->resultCode != FAUHDLC_EXIT_SUCCESS) || (this->topNode == NULL) || ast::ErrorRegistry::hasErrors()) { this->putCompileMessages(); return this->resultCode; } if (this->parseOnly) { return this->resultCode; } try { this->doSemanticAnalysis(); } catch (std::runtime_error f) { this->resultCode = FAUHDLC_EXIT_EXCEPTION; std::cerr << f.what() << std::endl; } catch (ast::CompileError ce) { this->resultCode = FAUHDLC_EXIT_EXCEPTION; std::cerr << "ERROR> " << ce << std::endl; } catch (...) { this->resultCode = FAUHDLC_EXIT_EXCEPTION; std::cerr << "unknown exception occured." << std::endl; } this->putCompileMessages(); if (this->resultCode != FAUHDLC_EXIT_SUCCESS) { return this->resultCode; } try { this->doIntermediateTransform(); } catch (std::runtime_error f) { this->resultCode = FAUHDLC_EXIT_EXCEPTION; std::cerr << f.what() << std::endl; } catch (...) { this->resultCode = FAUHDLC_EXIT_EXCEPTION; std::cerr << "unknown exception occured." << std::endl; } return this->resultCode; } void FAUhdlc::doParse(void) { this->symbolTable = new ast::BuiltinSymbolTable(); yy::ParserDriver driver = yy::ParserDriver(*symbolTable); if (! this->freeStanding) { FAUhdlc::LibFile *lf = new FAUhdlc::LibFile(); lf->filename = new std::string( VHDL_DATA_DIR "/std_logic_1164.vhdl"); lf->library = "ieee"; this->sourceFiles.push_front(lf); } for (std::list::const_iterator i = this->sourceFiles.begin(); i != this->sourceFiles.end(); i++) { try { driver.parse(*((*i)->filename), (*i)->library); } catch (yy::SyntaxError e) { if (ast::ErrorRegistry::hasErrors()) { // don't report syntax errors, there are // other, probably more accute errors this->resultCode = FAUHDLC_EXIT_ERROR; return; } std::cerr << e.what() << std::endl; this->resultCode = FAUHDLC_EXIT_ERROR; return; } catch (std::runtime_error g) { std::cerr << g.what() << std::endl; this->resultCode = FAUHDLC_EXIT_EXCEPTION; return; } catch (ast::CompileError h) { std::cerr << "ERROR> " << h << std::endl; } catch (...) { std::cerr << "unknown exception occured." << std::endl; this->resultCode = FAUHDLC_EXIT_EXCEPTION; return; } } this->topNode = driver.topNode; if (this->topNode == NULL) { this->resultCode = FAUHDLC_EXIT_EXCEPTION; return; } // dot graph after parsing? if (this->dotParse) { #ifdef DEBUG std::cerr << "========= DOT VISITOR ==========" << std::endl; #endif ast::DotVisitor v = ast::DotVisitor(); this->topNode->accept(v); std::ofstream stream; stream.open(this->dotParseFile, std::ofstream::out); v.put(stream); stream.close(); } } void FAUhdlc::putCompileMessages(void) { // write warnings if any if (ast::ErrorRegistry::hasWarnings()) { ast::ErrorRegistry::putWarnings(std::cerr); } // write errors if any if (ast::ErrorRegistry::hasErrors()) { ast::ErrorRegistry::putErrors(std::cerr); std::cerr << std::endl; this->resultCode = FAUHDLC_EXIT_ERROR; } } void FAUhdlc::doSemanticAnalysis(void) { #ifdef DEBUG std::cerr << "======= TRANSFORM SIGASSIGNS =====" << std::endl; #endif ast::TransformSigAssign tsa = ast::TransformSigAssign(); this->topNode->accept(tsa); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= RESOLVE TYPES ==========" << std::endl; #endif ast::ResolveTypes rt = ast::ResolveTypes(*this->symbolTable); this->topNode->accept(rt); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= PROPAGATE CONSTANT ========" << std::endl; #endif ast::ConstantPropagation cp = ast::ConstantPropagation(); this->topNode->accept(cp); if (ast::ErrorRegistry::hasErrors()) { return; } if (this->dotConst) { #ifdef DEBUG std::cerr << "========= DOT VISITOR ==========" << std::endl; #endif ast::DotVisitor v = ast::DotVisitor(); this->topNode->accept(v); std::ofstream stream; stream.open(this->dotConstFile, std::ofstream::out); v.put(stream); stream.close(); } #ifdef DEBUG std::cerr << "========= CHECK LOOPS ========" << std::endl; #endif ast::CheckLoops cl = ast::CheckLoops(); this->topNode->accept(cl); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= NORMALIZE ASSOCS ========" << std::endl; #endif ast::NormalizeAssocLists na = ast::NormalizeAssocLists(); this->topNode->accept(na); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= CHECK ACCESS MODE ========" << std::endl; #endif ast::CheckAccessMode cam = ast::CheckAccessMode(); this->topNode->accept(cam); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "=========== WARN UNUSED ===========" << std::endl; #endif ast::WarnUnused wuu = ast::WarnUnused(); this->topNode->accept(wuu); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= GATHER IMPLICITS ========" << std::endl; #endif ast::GatherImplicits giv = ast::GatherImplicits(); this->topNode->accept(giv); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= SET PATH NAMES ==========" << std::endl; #endif ast::SetPathName spn = ast::SetPathName(); this->topNode->accept(spn); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= CHECK WAIT CONDS ========" << std::endl; #endif ast::WaitConditions cwc = ast::WaitConditions(); this->topNode->accept(cwc); if (ast::ErrorRegistry::hasErrors()) { return; } #ifdef DEBUG std::cerr << "========= GENERATE ICODE =========" << std::endl; #endif ast::GenCode gc = ast::GenCode(); this->topNode->accept(gc); if (ast::ErrorRegistry::hasErrors()) { return; } this->iTopNode = gc.container; } void FAUhdlc::doIntermediateTransform(void) { intermediate::LookupSymbols ls = intermediate::LookupSymbols(); assert(this->iTopNode != NULL); this->iTopNode->accept(ls); this->printICode(); this->genCCode(); } void FAUhdlc::printICode(void) { if (this->outputFile == NULL) { return; } std::ofstream out; out.open(this->outputFile, std::ofstream::out); if (! out.good()) { out.close(); std::cerr << "Couldn't open " << this->outputFile << " for writing." << std::endl; return; } intermediate::PrintCode pc = intermediate::PrintCode(out); assert(this->iTopNode != NULL); this->iTopNode->accept(pc); out.close(); } void FAUhdlc::genCCode(void) { if (this->cFile == NULL) { return; } std::ofstream out; out.open(this->cFile, std::ofstream::out); if (! out.good()) { out.close(); std::cerr << "Couldn't open " << this->cFile << " for writing." << std::endl; return; } intermediate::GenCCode gcv = intermediate::GenCCode(out); assert(this->iTopNode != NULL); this->iTopNode->accept(gcv); out.close(); } void FAUhdlc::usage(std::ostream &out) const { out << "FAUhdlc a VHDL to C compiler" << std::endl; out << std::endl; out << "Usage: fauhdlc [OPTIONS] files" << std::endl; out << "OPTIONS:" << std::endl; out << "\t--help \tDisplay this help." << std::endl; out << "\t-o filaneme " << "\tOutput to file filename." << std::endl; out << "\t--parse-only " << "\tstop with semantic analysis after parsing." << std::endl; out << "\t--dot-parse=filename" << "\tCreate a dot-file called filename after parsing." << std::endl; out << "\t--dot-const=filename" << "\tCreate a dot-file called filename after const. propagation." << std::endl; out << "\t--lib=library " << "\tAll following files belong to library." << std::endl; out << "\t-Werror " << "\tReport warnings as errors." << std::endl; out << "\t--freestanding " << "\tFreestanding mode (don't load std_logic)." << std::endl; out << "\t--c-output " << "\tCreate output filename in C language." << std::endl; out << std::endl; out << "For each source file, a separate library may be specified." << std::endl; out << "If no library has been specified, 'work' will be used." << std::endl; out << std::endl; out << "Exit codes:" << std::endl; out << "\t1\twrong command line parameters." << std::endl; out << "\t3\tcompile error was found failed." << std::endl; out << "\t4\tOther exception occurred." << std::endl; out << std::endl; } }; /* namespace compiler */ int main(int argc, char** argv) { util::GarbageCollect::initialize(); compiler::FAUhdlc fauhdlc = compiler::FAUhdlc(); fauhdlc.parseCmdLine(argc, argv); return fauhdlc.run(); } fauhdlc-20130704/lib/0000775000175000017500000000000012165333077013557 5ustar potyrapotyrafauhdlc-20130704/lib/runtime.h0000664000175000017500000001212711726230621015407 0ustar potyrapotyra/* $Id: runtime.h 5110 2012-03-08 22:24:17Z potyra $ * * C-Code kernel / runtime library. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ /* FIXME: name too generic? * FIXME: cleanup between stuff in interpreter and this file. */ #ifndef __RUNTIME_H_INCLUDED #define __RUNTIME_H_INCLUDED #include #include #include #include #include #include #include #include #include #define ALWAYS_INLINE inline __attribute__((__always_inline__)) union vhdl_value { universal_integer univ_int; universal_integer univ_real; }; struct vhdl_kernel { struct slset *signals; struct slset *processes; universal_integer sim_time; struct slset *drivers; struct slset *run_q; struct slset *wait_q; struct slset *create_q; }; struct vhdl_process { pthread_t thread; pthread_mutex_t sleeping; struct slset *sensitivities; universal_integer next_event; void *stack_frame; }; struct signal { union vhdl_value value; struct slset *connected_drivers; bool event; /* FIXME resolution function */ }; struct drv_trans { universal_integer sim_time; union vhdl_value val; }; struct driver { union vhdl_value driving_value; struct signal *connected_signal; bool active; struct slset *transactions; }; static ALWAYS_INLINE universal_integer signal_read_int(const struct signal *sig) { return sig->value.univ_int; } static ALWAYS_INLINE universal_real signal_read_real(const struct signal *sig) { return sig->value.univ_real; } static ALWAYS_INLINE struct signal * signal_create(struct vhdl_kernel *kernel, const char *name) { struct signal *sig = malloc(sizeof(struct signal)); assert(sig != NULL); /* FIXME initial value */ sig->value.univ_int = 0; sig->connected_drivers = slset_create(NULL, malloc); sig->event = false; slset_add(kernel->signals, sig, malloc); return sig; } static int __attribute__((__pure__)) drv_trans_compare(const void *_t1, const void *_t2) { const struct drv_trans *t1 = (const struct drv_trans *)_t1; const struct drv_trans *t2 = (const struct drv_trans *)_t2; if (t1->sim_time < t2->sim_time) { return -1; } if (t1->sim_time == t2->sim_time) { return 0; } return 1; } static ALWAYS_INLINE struct driver * driver_create(struct vhdl_kernel *kernel) { struct driver *drv = malloc(sizeof(struct driver)); assert(drv != NULL); /* FIXME initial value */ drv->driving_value.univ_int = 0; drv->connected_signal = NULL; drv->transactions = slset_create(drv_trans_compare, malloc); drv->active = false; slset_add(kernel->drivers, drv, malloc); return drv; } static ALWAYS_INLINE void driver_connect(struct driver *drv, struct signal *s) { assert(drv != NULL); assert(s != NULL); slset_add(s->connected_drivers, drv, malloc); drv->connected_signal = s; } static ALWAYS_INLINE void driver_update_int_after( struct driver *drv, universal_integer sim_time, universal_integer value ) { struct drv_trans *t = malloc(sizeof(struct drv_trans)); assert(t != NULL); t->sim_time = sim_time; t->val.univ_int = value; slset_truncate_at(drv->transactions, t, true, free); slset_add(drv->transactions, t, malloc); } static ALWAYS_INLINE void driver_update_real_after( struct driver *drv, universal_integer sim_time, universal_real value ) { struct drv_trans *t = malloc(sizeof(struct drv_trans)); assert(t != NULL); t->sim_time = sim_time; t->val.univ_real = value; slset_truncate_at(drv->transactions, t, true, free); slset_add(drv->transactions, t, malloc); } static ALWAYS_INLINE struct vhdl_process * sched_create_process( struct vhdl_kernel *kernel, void *sf, void *(*fun)(void *) ) { struct vhdl_process *proc = malloc(sizeof(struct vhdl_process)); int ret; assert(proc != NULL); proc->sensitivities = slset_create(NULL, malloc); proc->next_event = INT64_MAX; proc->stack_frame = sf; do { ret = pthread_mutex_init(&proc->sleeping, NULL); assert((ret == 0) || (ret == EAGAIN)); } while (ret == EAGAIN); slset_add(kernel->create_q, proc, malloc); return proc; } static ALWAYS_INLINE void sched_wake_on(struct vhdl_process *proc, struct signal *sensitivity) { slset_add(proc->sensitivities, sensitivity, malloc); } static ALWAYS_INLINE void sched_suspend(struct vhdl_kernel *kernel, struct vhdl_process *proc) { int ret; ret = pthread_mutex_lock(&proc->sleeping); /* FIXME decrease *shared* number of running processes */ assert(ret == 0); } static ALWAYS_INLINE void sched_abort(void) { /* FIXME */ } static ALWAYS_INLINE void vhdl_log(universal_integer severity, universal_integer c) { switch (severity) { case 3: /* failure */ fprintf(stdout, "FAILURE: "); break; case 2: /* error */ fprintf(stdout, "ERROR: "); break; case 1: /* warning */ fprintf(stdout, "WARNING: "); break; case 0: /* note */ fprintf(stdout, "NOTE: "); break; default: break; } fprintf(stdout, "%c", (int)c); } #endif /* __RUNTIME_H_INCLUDED */ fauhdlc-20130704/lib/std_logic_1164.vhdl0000664000175000017500000001413511311447720017055 0ustar potyrapotyra-- $Id: std_logic_1164.vhdl 4912 2009-12-14 14:46:40Z potyra $ -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. -- FIXME doesn't match the real std_logic_1164 yet. PACKAGE std_logic_1164 IS TYPE std_ulogic IS ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'); TYPE std_ulogic_vector IS array (NATURAL range <>) of std_ulogic; FUNCTION resolve_stdlogic(s : std_ulogic_vector) RETURN std_ulogic; SUBTYPE std_logic IS resolve_stdlogic std_ulogic; TYPE std_logic_vector IS array (NATURAL range <>) of std_logic; function "xor"(l: std_ulogic; r: std_ulogic) return std_ulogic; function "and"(l: std_ulogic; r: std_ulogic) return std_ulogic; function "or"(l: std_ulogic; r: std_ulogic) return std_ulogic; function "not"(o: std_ulogic) return std_ulogic; END PACKAGE std_logic_1164; PACKAGE BODY std_logic_1164 IS function resolve_stdlogic(s : std_ulogic_vector) RETURN std_ulogic IS variable ret : std_ulogic; begin ret := s(0); for i in s'range loop case s(i) is when 'U' => return 'U'; when 'X' => case ret is when 'U' => return 'U'; when others => ret := 'X'; end case; when '0' => case ret is when 'U' => return 'U'; when 'X' => ret := 'X'; when '0' => ret := '0'; when '1' => ret := 'X'; when 'Z' => ret := '0'; when 'W' => ret := '0'; when 'L' => ret := '0'; when 'H' => ret := '0'; when '-' => ret := 'X'; end case; when '1' => case ret is when 'U' => return 'U'; when 'X' => ret := 'X'; when '0' => ret := 'X'; when '1' => ret := '1'; when 'Z' => ret := '1'; when 'W' => ret := '1'; when 'L' => ret := '1'; when 'H' => ret := '1'; when '-' => ret := 'X'; end case; when 'Z' => case ret is when 'U' => return 'U'; when 'X' => ret := 'X'; when '0' => ret := '0'; when '1' => ret := '1'; when 'Z' => ret := 'Z'; when 'W' => ret := 'W'; when 'L' => ret := 'L'; when 'H' => ret := 'H'; when '-' => ret := 'X'; end case; when 'W' => case ret is when 'U' => return 'U'; when 'X' => ret := 'X'; when '0' => ret := '0'; when '1' => ret := '1'; when 'Z' => ret := 'W'; when 'W' => ret := 'W'; when 'L' => ret := 'W'; when 'H' => ret := 'W'; when '-' => ret := 'X'; end case; when 'L' => case ret is when 'U' => return 'U'; when 'X' => ret := 'X'; when '0' => ret := '0'; when '1' => ret := '1'; when 'Z' => ret := 'L'; when 'W' => ret := 'W'; when 'L' => ret := 'L'; when 'H' => ret := 'W'; when '-' => ret := 'X'; end case; when 'H' => case ret is when 'U' => return 'U'; when 'X' => ret := 'X'; when '0' => ret := '0'; when '1' => ret := '1'; when 'Z' => ret := 'H'; when 'W' => ret := 'W'; when 'L' => ret := 'W'; when 'H' => ret := 'H'; when '-' => ret := 'X'; end case; when '-' => case ret is when 'U' => return 'U'; when 'X' => ret := 'X'; when '0' => ret := 'X'; when '1' => ret := 'X'; when 'Z' => ret := 'X'; when 'W' => ret := 'X'; when 'L' => ret := 'X'; when 'H' => ret := 'X'; when '-' => ret := 'X'; end case; end case; end loop; return ret; end; function "xor"(l: std_ulogic; r: std_ulogic) return std_ulogic IS begin case l is when 'U' => return 'U'; when 'X' | 'Z' | 'W' | '-' => case r is when 'U' => return 'U'; when others => return 'X'; end case; when '0' | 'L' => case r is when 'U' => return 'U'; when 'X' => return 'X'; when '0' => return '0'; when '1' => return '1'; when 'Z' => return 'X'; when 'W' => return 'X'; when 'L' => return '0'; when 'H' => return '1'; when '-' => return 'X'; end case; when '1' | 'H' => case r is when 'U' => return 'U'; when 'X' => return 'X'; when '0' => return '1'; when '1' => return '0'; when 'Z' => return 'X'; when 'W' => return 'X'; when 'L' => return '1'; when 'H' => return '0'; when '-' => return 'X'; end case; end case; end; function "and"(l: std_ulogic; r: std_ulogic) return std_ulogic IS begin case l is when '0' | 'L' => return '0'; when 'U' => case r is when '0' | 'L' => return '0'; when others => return 'U'; end case; when '1' | 'H' => case r is when 'U' => return 'U'; when 'X' => return 'X'; when '0' => return '0'; when '1' => return '1'; when 'Z' => return 'X'; when 'W' => return 'X'; when 'L' => return '0'; when 'H' => return '1'; when '-' => return 'X'; end case; when 'X' | 'Z' | 'W' | '-' => case r is when 'U' => return 'U'; when 'X' => return 'X'; when '0' => return '0'; when '1' => return 'X'; when 'Z' => return 'X'; when 'W' => return 'X'; when 'L' => return '0'; when 'H' => return 'X'; when '-' => return 'X'; end case; end case; end; function "or"(l: std_ulogic; r: std_ulogic) return std_ulogic IS begin case l is when '1' | 'H' => return '1'; when 'U' => case r is when '1' | 'H' => return '1'; when others => return 'U'; end case; when '0' | 'L' => case r is when 'U' => return 'U'; when 'X' => return 'X'; when '0' => return '0'; when '1' => return '1'; when 'Z' => return 'X'; when 'W' => return 'X'; when 'L' => return '0'; when 'H' => return '1'; when '-' => return 'X'; end case; when 'X' | 'Z' | 'W' | '-' => case r is when 'U' => return 'U'; when 'X' => return 'X'; when '0' => return 'X'; when '1' => return '1'; when 'Z' => return 'X'; when 'W' => return 'X'; when 'L' => return 'X'; when 'H' => return '1'; when '-' => return 'X'; end case; end case; end; function "not"(o: std_ulogic) return std_ulogic IS begin case o is when 'U' => return 'U'; when 'X' | 'Z' | 'W' | '-' => return 'X'; when '0' | 'L' => return '1'; when '1' | 'H' => return '0'; end case; end; END PACKAGE; fauhdlc-20130704/lib/ckernel.c0000664000175000017500000000542711462045115015346 0ustar potyrapotyra/* $Id: ckernel.c 5062 2010-10-27 15:50:37Z potyra $ * * C-Code kernel / runtime library.. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #ifndef _GNU_SOURCE #define _GNU_SOURCE #include #undef _GNU_SOURCE #else /* _GNU_SOURCE already defined */ #include #endif /* _GNU_SOURCE not defined? */ #include #include #include #include #include "mangle_names.h" #include "basetypes.h" #include "runtime.h" /* init routine as defined by the c-file */ extern int vhdl_call_by_name(struct vhdl_kernel *kernel, const char *name); #if 0 /* FIXME */ static int simulation_cycle(void) { for (;;) { /* advance simulation time to next event */ /* update signals from driving values */ /* wake up all processes with events */ /* resume all processes with events */ /* check for delta cycle, if so back to start */ /* here's a good place to call the tracer */ } } #endif static int start_simulation(const char *top_entity) { char buf[2048]; int ret; ret = mangle_name(top_entity, buf, sizeof(buf)); assert(0 <= ret); assert((size_t)ret < sizeof(buf)); #if 0 /* FIXME */ ret = vhdl_call_by_name(buf); /* TODO */ #endif return ret; } static void usage(const char *prog) { fprintf(stderr, "%s [options]\n", prog); fprintf(stderr, " Generated VHDL Simulator.\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -s ENTITY, --simulate=ENTITY Start simulation " "with ENTITY as top entity.\n"); fprintf(stderr, " -o VCDFILE, --output=VCDFILE Output trace to "); fprintf(stderr, "VCDFILE.\n"); fprintf(stderr, " -t, --trace=ENTITY Trace all signals " "in ENTITY\n"); fprintf(stderr, " -h, --help Show this help."); fprintf(stderr, "\n"); } int main(int argc, char **argv) { int c; int ret; const char *top_entity = NULL; const char *trace_file = NULL; const struct option l_opts[] = { {"simulate", 1, NULL, 's'}, {"output", 1, NULL, 'o'}, {"trace", 1, NULL, 't'}, {"help", 0, NULL, 'h'}, {0, 0, 0, 0} }; for (;;) { c = getopt_long(argc, argv, "s:o:t:h", l_opts, NULL); if (c == -1) { break; } switch (c) { case 's': top_entity = optarg; break; case 'o': trace_file = optarg; break; case 't': assert(0); /* FIXME */ break; case 'h': usage(argv[0]); return EXIT_SUCCESS; default: usage(argv[0]); return EXIT_FAILURE; } } if (argc - optind != 0) { usage(argv[0]); return EXIT_FAILURE; } /* FIXME tracer... */ ret = start_simulation(top_entity); return ret; } fauhdlc-20130704/lib/Makefile.am0000664000175000017500000000072111462031264015603 0ustar potyrapotyra# $Id: Makefile.am 5058 2010-10-27 14:09:56Z potyra $ INCLUDES=-I$(top_srcdir)/interpreter/util \ -I$(top_srcdir)/util \ -I$(top_srcdir) dist_pkgdata_DATA=\ std_logic_1164.vhdl lib_LIBRARIES=libfauhdlk.a libfauhdlk_a_SOURCES=\ \ $(top_srcdir)/interpreter/util/list.c\ $(top_srcdir)/interpreter/util/slset.c\ \ $(top_srcdir)/util/mangle_names.c\ \ ckernel.c devel: $(CURDIR)/$(top_srcdir)/misc/install_ln.sh $(MAKE) install INSTALL=$< .PHONY: devel fauhdlc-20130704/intermediate/0000775000175000017500000000000012165333100015446 5ustar potyrapotyrafauhdlc-20130704/intermediate/container/0000775000175000017500000000000012165333077017445 5ustar potyrapotyrafauhdlc-20130704/intermediate/container/LabelFactory.cpp0000664000175000017500000000221111137610234022503 0ustar potyrapotyra/* $Id: LabelFactory.cpp 4323 2009-01-27 13:48:12Z potyra $ * * LabelFactory: generate labels and keep book on these. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "intermediate/container/LabelFactory.hpp" #include #include namespace intermediate { Label* LabelFactory::getLabel(const char *prefix) { std::stringstream stream; stream << prefix << "_" << LabelFactory::cnt; std::string s = stream.str(); LabelFactory::cnt++; return new Label(s); } Label* LabelFactory::getFixedLabel(const char *name) { return new Label(std::string(name)); } Label* LabelFactory::getFixedLabel(const std::string &name) { return new Label(name); } Label* LabelFactory::getErrorLabel(void) { static Label *errLabel = NULL; if (errLabel == NULL) { errLabel = new Label("vhdl_error"); return errLabel; } return errLabel; } int LabelFactory::cnt = 0; }; /* namespace intermediate */ fauhdlc-20130704/intermediate/container/Type.hpp0000664000175000017500000000267311137610234021076 0ustar potyrapotyra/* $Id: Type.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_HPP_INCLUDED #define __TYPE_HPP_INCLUDED #include #include #include "intermediate/container/TypeElement.hpp" namespace intermediate { //! declaration of a type /** * TYPE foo : bar[20]; * TYPE bar : universal_integer := -1, universal_integer := -5, * universal_real := 3.14, foobar; */ class Type : public Node { private: friend class TypeFactory; //! c'tor /** @param typeName declared name of the type. * @param relements list of elements of a composite type. */ Type( std::string typeName, std::list relements ) : name(typeName), elements(relements) {} public: //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } /** name of the declared type */ std::string name; /** list of elements for composite types, or one element for * non-composite types. */ std::list elements; }; }; /* namespace intermediate */ #endif /* __TYPE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/container/CodeContainer.hpp0000664000175000017500000000777211461537667022721 0ustar potyrapotyra/* $Id: CodeContainer.hpp 5044 2010-10-26 11:47:03Z potyra $ * * CodeContainer: can contain code and data and subcontainers. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CODE_CONTAINER_HPP_INCLUDED #define __CODE_CONTAINER_HPP_INCLUDED #include #include "intermediate/Node.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/container/Type.hpp" #include "intermediate/operands/RegisterFactory.hpp" namespace intermediate { //! can contain arbitrary seqences of code. /** The CodeContainer can contain various intermediate code, and can be * nested in itself. * The text segment of a code container resembles exactly one function, * which has the same name as the code container itself. The * transfer segment denotes the parameters passed to the function. * Subcontainers may denote other functions, which however may only * be called from inside the container itself. * The stack segment contains the locals of the funtion. */ class CodeContainer : public Node { public: enum DataModeE { /** data should get added to the stack segment */ DATA_STACK, /** data should get added to the transfer segment */ DATA_TRANSFER }; //! c'tor /** @param n name of the CodeContainer. The name of the code * container can be used in Call or Process statements. * @param parent parent CodeContainer, NULL for the outer most * CodeContainer. */ CodeContainer(std::string n, CodeContainer *parent) : name(n), dataMode(DATA_STACK), regFab(RegisterFactory()), nestingLevel(parent == NULL ? 0 : parent->nestingLevel + 1), staticParent(parent) { if (parent != NULL) { parent->children.push_back(this); } } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! add a piece of intermediate code to the container. /** @param n node to add to the container. */ void addCode(Node *n) { this->code.push_back(n); } //! add data to the container. /** @param n data to add to the container. */ void addData(Data *n) { switch (this->dataMode) { case DATA_STACK: this->stackData.push_back(n); break; case DATA_TRANSFER: this->transferData.push_back(n); break; } n->nestingLevel = this->nestingLevel; } //! add a type defintion to the container /** @param t type definition to add. */ void addType(Type *t) { this->typeDefinitions.push_back(t); } //! create a virtual register /** @param type type of the virtual register operand * @return newly created virtual register. */ Register* createRegister(enum OpType type) { return this->regFab.getReg(type); } /** return the number of virtual registers that are used by this * CodeContainer. * @return number of used virtual registers. */ size_t getNumUsedRegs(void) const { return this->regFab.getNumUsedRegs(); } /** child code containers. Will get evaluated *before* the current * container. */ std::list children; /** list of Type definitions covering stack and transfer data. */ std::list typeDefinitions; /** data that should be stored on the local stack */ std::list stackData; /** transfer data (parameters) */ std::list transferData; //! code contained in the container. std::list code; //! name of the container std::string name; //! default data mode enum DataModeE dataMode; //! associated RegisterFactory instance. RegisterFactory regFab; //! nesting level (outmost=0) unsigned int nestingLevel; //! parent code container const CodeContainer *staticParent; protected: virtual ~CodeContainer() {} }; }; /* namespace intermediate */ #endif /* __CODE_CONTAINER_HPP_INCLUDED */ fauhdlc-20130704/intermediate/container/Label.hpp0000664000175000017500000000202311137610234021161 0ustar potyrapotyra/* $Id: Label.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LABEL_HPP_INCLUDED #define __LABEL_HPP_INCLUDED #include "intermediate/Node.hpp" #include namespace intermediate { //! a label, which marks the destination of a jump class Label : public Node { public: //! c'tor /** @param id name of the label */ Label(std::string id) : name(id) {} //! virtual dummy d'tor virtual ~Label() {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! name of the label. std::string name; }; }; /* namespace intermediate */ #endif /* __LABEL_HPP_INCLUDED */ fauhdlc-20130704/intermediate/container/TypeFactory.cpp0000664000175000017500000000312711173106127022415 0ustar potyrapotyra/* $Id: TypeFactory.cpp 4475 2009-04-20 14:53:11Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "intermediate/container/TypeFactory.hpp" #include namespace intermediate { TypeFactory::typesNameT TypeFactory::typesByName = TypeFactory::initialize(); TypeFactory::typesNameT TypeFactory::initialize(void) { TypeFactory::typesNameT ret = typesNameT(); Type *t = new Type("universal_integer", std::list()); ret["universal_integer"] = t; t = new Type("universal_real", std::list()); ret["universal_real"] = t; return ret; } std::string TypeFactory::getTypeName(enum ast::BaseType bt) { switch(bt) { case ast::BASE_TYPE_INTEGER: return std::string("universal_integer"); case ast::BASE_TYPE_REAL: case ast::BASE_TYPE_ENUM: return std::string("universal_real"); default: assert(false); } // not reached. // make g++ happy return std::string("error: not reached"); } Type * TypeFactory::getType(std::string typeName, std::list relements) { Type *t = new Type(typeName, relements); TypeFactory::typesByName[typeName] = t; return t; } Type * TypeFactory::lookupType(std::string typeName) { typesNameT::const_iterator i = TypeFactory::typesByName.find(typeName); if (i != TypeFactory::typesByName.end()) { return i->second; } return NULL; } }; /* namespace intermediate */ fauhdlc-20130704/intermediate/container/TypeFactory.hpp0000664000175000017500000000311211137610234022413 0ustar potyrapotyra/* $Id: TypeFactory.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_FACTORY_HPP_INCLUDED #define __TYPE_FACTORY_HPP_INCLUDED #include "frontend/ast/Types.hpp" #include "intermediate/container/Type.hpp" #include #include #include namespace intermediate { //! generate builtin class TypeFactory { public: /** create a type with a name and a number of elements. * @param typeName declared name of the type. * @param relements list of elements of a composite type. */ static Type* getType( std::string typeName, std::list relements ); /** return the type name that corresponds to a base type. * @param bt base type (either integer or real) * @return fitting name to be used in intermediate code. */ static std::string getTypeName(enum ast::BaseType bt); /** lookup a type by the intermediate code name. * @return the found type or NULL if no such type is known. */ static Type* lookupType(std::string typeName); private: // FIXME use hash_map or s.th. typedef std::map typesNameT; /** info about created types by name */ static typesNameT typesByName; /** initialize typesByName with builtins */ static typesNameT initialize(void); }; }; /* namespace intermediate */ #endif /* __TYPE_FACTORY_HPP_INCLUDED */ fauhdlc-20130704/intermediate/container/Data.hpp0000664000175000017500000000364711460325511021030 0ustar potyrapotyra/* $Id: Data.hpp 5016 2010-10-22 15:18:33Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DATA_HPP_INCLUDED #define __DATA_HPP_INCLUDED #include #include "intermediate/container/TypeElement.hpp" namespace intermediate { //! different storage types (objects lying somewhere on the heap or stack) enum StorageType { //! plain variable. STORAGE_TYPE_VARIABLE, //! a driver of a signal STORAGE_TYPE_DRIVER, //! a signal (which however first needs to be created) STORAGE_TYPE_SIGNAL }; //! declaration of a data object class Data : public Node { public: //! c'tor /** @param n name of the data object * @param st storage type of the object * @param t type element of the data object * @param rf resolution function (NULL means unresolved). */ Data( std::string n, enum StorageType st, TypeElement *t, std::string *rf ) : name(n), storage(st), dataType(t), resolver(rf), nestingLevel(0) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } /** name of the data object */ std::string name; /** storage type */ enum StorageType storage; /** type of the data object, eventually with initializer */ TypeElement *dataType; /** resolution function (NULL means unresolved) */ std::string *resolver; //! nesting level (outmost=0). @see CodeContainer. unsigned int nestingLevel; protected: virtual ~Data() { util::MiscUtil::terminate(this->dataType); util::MiscUtil::terminate(this->resolver); } }; }; /* namespace intermediate */ #endif /* __DATA_HPP_INCLUDED */ fauhdlc-20130704/intermediate/container/LabelFactory.hpp0000664000175000017500000000303711137610234022517 0ustar potyrapotyra/* $Id: LabelFactory.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LABEL_FACTORY_HPP_INCLUDED #define __LABEL_FACTORY_HPP_INCLUDED #include "intermediate/container/Label.hpp" namespace intermediate { //! produce uniquely named labels. class LabelFactory { public: //! get a label with prefix prefix /** @param prefix desired prefix of the label. * @return Label with a unique name. */ static Label *getLabel(const char *prefix); //! get a label with a fixed name. /** No checks are performed, if this label is unique. * @param name desired name of the label. * @return Label with the requested name. */ static Label *getFixedLabel(const char *name); //! get a label with a fixed name. /** No checks are performed, if this label is unique. * @param name desired name of the label. * @return Label with the requested name. */ static Label *getFixedLabel(const std::string &name); //! get a label pointing to an unparametrized error function. /** Use this method to get a lable that can be jumped to in case * an error occurs (e.g. constraint violations etc.) */ static Label *getErrorLabel(void); private: // internal Label counter static int cnt; }; }; /* namespace intermediate */ #endif /* __LABEL_FACTORY_HPP_INCLUDED */ fauhdlc-20130704/intermediate/container/TypeElement.hpp0000664000175000017500000000375411164160070022407 0ustar potyrapotyra/* $Id: TypeElement.hpp 4442 2009-03-30 15:07:36Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_ELEMENT_HPP_INCLUDED #define __TYPE_ELEMENT_HPP_INCLUDED #include #include #include #include "frontend/ast/Types.hpp" #include "intermediate/operands/ImmediateOperand.hpp" namespace intermediate { //! element of a type class TypeElement : public Node { public: //! c'tor /** @param typeName element is of this type. * @param initV initial value(s) of the type/or of the data instance. * @param upperBound: upper bound for arrays (0-based, excl. u.b.) */ TypeElement( std::string typeName, std::list initV, universal_integer upperBound ) : name(typeName), init(initV), ubound(upperBound) { } //! alternate c'tor /** * This constructor can be used for elements wich are * not array (i.e. upper bound 1). * @param typeName element is of this type. * @param initV initial value(s) */ TypeElement( std::string typeName, std::list initV ) : name(typeName), init(initV), ubound(1) { } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } /** name of the type that the element refers to. */ std::string name; /** initial values (may be empty, for uninitialized types) */ std::list init; /** upper bound for arrays. > 0, 1 means that it is no array. * The array has the bounds [0, ubound[. */ universal_integer ubound; protected: virtual ~TypeElement() {} }; }; /* namespace intermediate */ #endif /* __TYPE_ELEMENT_HPP_INCLUDED */ fauhdlc-20130704/intermediate/visitor/0000775000175000017500000000000012165333077017162 5ustar potyrapotyrafauhdlc-20130704/intermediate/visitor/GenCCode.cpp0000664000175000017500000004160011462321637021274 0ustar potyrapotyra/* $Id: GenCCode.cpp 5073 2010-10-28 16:23:59Z potyra $ * * Generate C-Code from intermediate code. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "intermediate/visitor/GenCCode.hpp" #include #include "intermediate/opcodes/Connect.hpp" #include "intermediate/opcodes/Je.hpp" #include "intermediate/opcodes/Jne.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Jbe.hpp" #include "intermediate/opcodes/Jmp.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Abort.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/opcodes/IMul.hpp" #include "intermediate/opcodes/Div.hpp" #include "intermediate/opcodes/Call.hpp" #include "intermediate/opcodes/Return.hpp" #include "intermediate/opcodes/Proc.hpp" #include "intermediate/opcodes/Update.hpp" #include "intermediate/opcodes/GetSig.hpp" #include "intermediate/opcodes/GetSimTime.hpp" #include "intermediate/opcodes/ROffset.hpp" #include "intermediate/opcodes/AOffset.hpp" #include "intermediate/opcodes/Suspend.hpp" #include "intermediate/opcodes/WakeOn.hpp" #include "intermediate/opcodes/WakeAt.hpp" #include "intermediate/opcodes/Log.hpp" #include "intermediate/opcodes/BeginTransfer.hpp" #include "intermediate/opcodes/EndTransfer.hpp" #include "intermediate/opcodes/SetParam.hpp" #include "intermediate/opcodes/GetParam.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/operands/IndirectOperand.hpp" #include "intermediate/operands/Reference.hpp" #include "intermediate/operands/Register.hpp" #include "intermediate/container/CodeContainer.hpp" #include "intermediate/container/Label.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/container/TypeElement.hpp" #include "intermediate/container/Type.hpp" namespace intermediate { /* Layout of stack frame: * struct container_sf { * struct vhdl_kernel *kernel; * struct vhdl_process *process; * struct _sf *static_parent; * * struct { * // transfer elements (parameters) * // local data definition * } data; * void *transfer; // allocated child stack frame * }; */ GenCCode::GenCCode(std::ostream &destination) : dst(destination), nestingLevel(0), funcs(std::list()), addFinale(true) { this->prelude(); } void GenCCode::visit(CodeContainer &node) { bool af = this->addFinale; this->addFinale = false; // register function to be called by name // that heuristic should match roughly the interpreter: // - not nested deeper than level 1 (that should be the architecture // create functions) // - no parameters // - and the function in question must exist. if ( (node.nestingLevel < 2) && node.transferData.empty() && (! node.code.empty())) { this->funcs.push_back(&node.name); } this->nestingLevel = node.nestingLevel; this->listTraverse(node.typeDefinitions); this->dst << "struct " << node.name << "_sf {" << std::endl; this->dst << "\tstruct vhdl_kernel *kernel;" << std::endl; this->dst << "\tstruct vhdl_process *process;" << std::endl; if (node.staticParent != NULL) { this->dst << "\tstruct " << node.staticParent->name << "_sf *static_parent;" << std::endl; } if ((! node.transferData.empty()) || (! node.stackData.empty())) { this->dst << "\tstruct {" << std::endl << "\t\t/* parameters */" << std::endl; this->listTraverse(node.transferData); this->dst << "\t\t/* local data */" << std::endl; this->listTraverse(node.stackData); this->dst << "\t} data;" << std::endl; } this->dst << "\tvoid *transfer;" << std::endl << "};" << std::endl; this->dst << std::endl; this->listTraverse(node.children); this->nestingLevel = node.nestingLevel; if (! node.code.empty()) { this->dst << "static void *" << std::endl; this->dst << node.name << "(void *_cpssp)" << std::endl; this->dst << "{" << std::endl; this->dst << "\tstruct " << node.name << "_sf *cpssp = (struct " << node.name << "_sf *)_cpssp;" << std::endl; // map registers to variables on the stack. this->genRegisters(node.regFab); this->dst << std::endl; this->initializeContainerData(node); this->listTraverse(node.code); this->dst << "}" << std::endl << std::endl; } if (af) { this->finale(); } } void GenCCode::genRegisters(const RegisterFactory ®Fab) { const std::vector &tv = regFab.getRegTypes(); size_t sz = 0; for (std::vector::const_iterator i = tv.begin(); i != tv.end(); i++, sz++) { this->dst << "\t"; this->putOpType(*i); this->dst << " reg_" << sz << ";" << std::endl; } } void GenCCode::initializeContainerData(const CodeContainer &container) { for (std::list::const_iterator i = container.stackData.begin(); i != container.stackData.end(); i++) { this->initializeData(**i); } // what about transfer data? does this need to get initialized as // well (wrt. default arguments maybe?) (FIXME) } void GenCCode::initializeData(const Data &data) { switch (data.storage) { case STORAGE_TYPE_VARIABLE: this->createVariable(data); break; case STORAGE_TYPE_DRIVER: this->createDriver(data); break; case STORAGE_TYPE_SIGNAL: this->createSignal(data); break; } } void GenCCode::createVariable(const Data &data) { if (data.dataType->init.empty()) { return; } if (1 < data.dataType->ubound) { // FIXME: arrays (how on earth are arrays handled again?) return; } this->dst << "\tcpssp->data." << data.name << " = "; (*data.dataType->init.begin())->accept(*this); this->dst << "; " << std::endl; } void GenCCode::createDriver(const Data &data) { if (data.dataType->ubound == 1) { this->dst << "\tcpssp->data." << data.name << " = driver_create(cpssp->kernel);" << std::endl; return; } for (universal_integer sz = 0; sz < data.dataType->ubound; sz++) { this->dst << "\tcpssp->data." << data.name << "[" << sz << "] = driver_create(cpssp->kernel);" << std::endl; } // FIXME: initializers } void GenCCode::createSignal(const Data &data) { if (data.dataType->ubound == 1) { this->dst << "\tcpssp->data." << data.name << " = signal_create(cpssp->kernel, \"" << data.name << "\");" << std::endl; return; } for (universal_integer sz = 0; sz < data.dataType->ubound; sz++) { this->dst << "\tcpssp->data." << data.name << "[" << sz << "] = signal_create(cpssp->kernel, \"" << data.name << "\");" << std::endl; } // FIXME: initializers } void GenCCode::visit(ImmediateOperand &node) { switch(node.type) { case OP_TYPE_REAL: this->dst << node.rValue << 'F'; break; case OP_TYPE_INTEGER: this->dst << static_cast(node.iValue) << "ULL " << "/* " << node.iValue << " */"; break; case OP_TYPE_POINTER: // illegal adressing mode: immediate pointer assert(false); break; } } void GenCCode::visit(BeginTransfer &node) { this->dst << "\tcpssp->transfer = malloc(sizeof(struct " << node.src->name << "_sf));" << std::endl << "\tassert(cpssp->transfer != NULL);" << std::endl; } void GenCCode::visit(EndTransfer &node) { if (node.cleanupStack) assert(node.cleanupStack->type == OP_TYPE_INTEGER); if (node.cleanupStack->iValue == 0) { this->dst << "\t/* EndTransfer: Stack still needed */" << std::endl; } else { this->dst << "\tfree(cpssp->transfer);" << std::endl; } } void GenCCode::visit(SetParam &node) { this->dst << "\t((struct " << node.container->name << "_sf *) cpssp->transfer)->data." << node.dst->name << " = "; node.src->accept(*this); this->dst << ";" << std::endl; } void GenCCode::visit(GetParam &node) { this->dst << "\t"; node.dst->accept(*this); this->dst << " = ((struct " << node.container->name << "_sf *) cpssp->transfer)->data." << node.src->name << ";" << std::endl; } void GenCCode::visit(Connect &node) { this->dst << "\tdriver_connect((struct driver *)"; node.driver->accept(*this); this->dst << ", (struct signal *)"; node.signal->accept(*this); this->dst << ");" << std::endl; } void GenCCode::visit(Mov &node) { this->dst << "\t"; node.dst->accept(*this); this->dst << " = "; node.src->accept(*this); this->dst << ";" << std::endl; } void GenCCode::visit(Je &node) { this->processCondJmp(node, "=="); } void GenCCode::visit(Jbe &node) { this->processCondJmp(node, "<="); } void GenCCode::visit(Jne &node) { this->processCondJmp(node, "!="); } void GenCCode::visit(Jb &node) { this->processCondJmp(node, "<"); } void GenCCode::visit(Jmp &node) { this->dst << "\tgoto " << node.trg->name << ";" << std::endl; } void GenCCode::visit(Label &node) { this->dst << node.name << ':' << std::endl; } void GenCCode::visit(Add &node) { this->processArith(node, "+"); } void GenCCode::visit(Abort &node) { this->dst << "\tsched_abort();" << std::endl; } void GenCCode::visit(Sub &node) { this->processArith(node, "-"); } void GenCCode::visit(Call &node) { assert(node.dst != NULL); this->chainStackFrames(*node.dst); this->dst << "\t((struct " << node.dst->name << "_sf *)cpssp->transfer)->process = cpssp->process;" << std::endl << "\t" << node.dst->name << "(cpssp->transfer);" << std::endl; } void GenCCode::visit(Return &node) { this->dst << "\treturn NULL;" << std::endl; } void GenCCode::visit(Proc &node) { assert(node.dst != NULL); this->chainStackFrames(*node.dst); this->dst << "\t((struct " << node.dst->name << "_sf *)cpssp->transfer)->process = " "sched_create_process(cpssp->kernel, cpssp->transfer, " << node.dst->name << ");" << std::endl; } void GenCCode::visit(Update &node) { switch (node.src->type) { case OP_TYPE_INTEGER: this->dst << "\tdriver_update_int_after((struct driver *)"; break; case OP_TYPE_REAL: this->dst << "\tdriver_update_real_after((struct driver *)"; break; case OP_TYPE_POINTER: assert(false); // not supported, must not happen. break; } node.dst->accept(*this); this->dst << ", "; node.delay->accept(*this); this->dst << ", "; node.src->accept(*this); this->dst << ");" << std::endl; } void GenCCode::visit(GetSig &node) { this->dst << "\t"; node.dst->accept(*this); this->dst << " = "; switch (node.dst->type) { case OP_TYPE_INTEGER: this->dst << "signal_read_int((struct signal *)"; break; case OP_TYPE_REAL: this->dst << "signal_read_real((struct signal *)"; break; case OP_TYPE_POINTER: assert(false); // not supported, must not happen. break; } node.src->accept(*this); this->dst << ");" << std::endl; } void GenCCode::visit(GetSimTime &node) { this->dst << "\t"; node.dst->accept(*this); this->dst << " = time_virt();" << std::endl; } void GenCCode::visit(IMul &node) { this->processArith(node, "*"); } void GenCCode::visit(Div &node) { this->processArith(node, "/"); } void GenCCode::visit(ROffset &node) { this->dst << "\t"; node.dst->accept(*this); this->dst << " = ((" << node.rtype->name << " *)&("; node.base->accept(*this); this->dst << "))->r" << node.offset->iValue << ";" << std::endl; } void GenCCode::visit(AOffset &node) { this->dst << "\t"; node.dst->accept(*this); // FIXME might need to override for signals this->dst << " = ((" << node.atype->name << " *)"; node.base->accept(*this); this->dst << ") + "; node.offset->accept(*this); this->dst << ";" << std::endl; } void GenCCode::visit(Suspend &node) { this->dst << "\tsched_suspend(cpssp->kernel, cpssp->process);" << std::endl; } void GenCCode::visit(WakeOn &node) { this->dst << "\tsched_wake_on(cpssp->process, (struct signal *)"; node.src->accept(*this); this->dst << ");" << std::endl; } void GenCCode::visit(WakeAt &node) { this->dst << "\tsched_wake_at(cpssp, "; node.wakeTime->accept(*this); this->dst << ");" << std::endl; } void GenCCode::visit(Log &node) { this->dst << "\tvhdl_log("; node.lvl->accept(*this); this->dst << ", "; node.c->accept(*this); this->dst << ");" << std::endl; } void GenCCode::visit(IndirectOperand &node) { this->dst << "(*("; this->putOpType(node.type); this->dst << " *)"; node.src->accept(*this); this->dst << ")"; } void GenCCode::visit(Reference &node) { assert(node.associatedData != NULL); assert(node.associatedData->nestingLevel <= this->nestingLevel); this->dst << "&cpssp->"; for (unsigned int i = node.associatedData->nestingLevel; i < this->nestingLevel; i++) { this->dst << "static_parent->"; } this->dst << "data." << node.name; } void GenCCode::visit(Register &node) { this->dst << "reg_" << node.num; } void GenCCode::visit(Data &node) { if (node.resolver) { this->dst << "/* FIXME the following signal is resolved */" << std::endl; } switch (node.storage) { case STORAGE_TYPE_VARIABLE: if (node.dataType->name == "__pointer__") { this->dst << "\t\tvoid *"; } else { this->dst << "\t\t" << node.dataType->name << " "; } break; case STORAGE_TYPE_DRIVER: this->dst << "\t\tstruct driver *"; break; case STORAGE_TYPE_SIGNAL: this->dst << "\t\tstruct signal *"; break; } this->dst << node.name; if (1 < node.dataType->ubound) { // FIXME braces correct for signals/drivers? this->dst << "[" << node.dataType->ubound << "]"; } this->dst << ";" << std::endl; } void GenCCode::visit(Type &node) { assert(! node.elements.empty()); // FIXME current type handling works only for non-signal types. // solution would be to define two typedefs, one for signals and // one for non-signals. The signals part should override // universal_integer and universal_real named TypeElements to // struct signal *. if (1 < node.elements.size()) { this->processRecord(node); } else { this->processArray(node); } } void GenCCode::visit(TypeElement &node) { this->dst << "/* FIXME TypeElement */" << std::endl; } void GenCCode::processRecord(Type &node) { this->dst << "typedef struct {" << std::endl; unsigned int cnt = 0; for (std::list::const_iterator i = node.elements.begin(); i != node.elements.end(); i++, cnt++) { this->processRecordElement(**i, cnt); } this->dst << "} " << node.name << ";" << std::endl; } void GenCCode::processArray(Type &node) { this->dst << "/* FIXME Array */" << std::endl; } void GenCCode::processRecordElement(TypeElement &node, unsigned int number) { this->dst << "\t" << node.name << " r" << number; if (node.ubound != 1) { this->dst << '[' << node.ubound << ']'; } this->dst << ";" << std::endl; if (! node.init.empty()) { this->dst << "/* FIXME initializer */" << std::endl; } } template void GenCCode::processCondJmp(T &node, const char *op) { this->dst << "\tif ("; node.left->accept(*this); this->dst << " " << op << " "; node.right->accept(*this); this->dst << ") {" << std::endl << "\t\tgoto " << node.trg->name << ";" << std::endl << "\t}" << std::endl; } template void GenCCode::processArith(T &node, const char *op) { this->dst << "\t"; node.dst->accept(*this); this->dst << " = "; node.left->accept(*this); this->dst << " " << op << " "; node.right->accept(*this); this->dst << ";" << std::endl; } void GenCCode::putOpType(const enum OpType t) { switch (t) { case OP_TYPE_INTEGER: this->dst << "universal_integer"; break; case OP_TYPE_REAL: this->dst << "universal_real"; break; case OP_TYPE_POINTER: this->dst << "void *"; break; } } void GenCCode::chainStackFrames(const Reference &callee) { assert(callee.associatedContainer != NULL); this->dst << "\t((struct " << callee.name << "_sf *)cpssp->transfer)->static_parent = cpssp"; // a: callee = 3, our=2 -> cpssp // b: callee = 2, our=2 -> cpssp->static_parent // c: callee = 1, our=2 -> cpssp->static_parent->static_parent for (unsigned int nl = this->nestingLevel; callee.associatedContainer->nestingLevel <= nl; nl--) { this->dst << "->static_parent"; } this->dst << ";" << std::endl; // also set pointer to kernel this->dst << "\t((struct " << callee.name << "_sf *)cpssp->transfer)->kernel = cpssp->kernel;" << std::endl; } void GenCCode::prelude(void) { // FIXME name of include file! this->dst << "#include " << std::endl << "/* Generated by fauhdlc */" << std::endl << std::endl; } void GenCCode::finale(void) { // TODO instance pointer? this->dst << std::endl << "int " << std::endl << "vhdl_call_by_name(struct vhdl_kernel *kernel, " "const char *name)" << std::endl << "{" << std::endl; for (std::list::const_iterator i = this->funcs.begin(); i != this->funcs.end(); i++) { this->dst << "\tif (strcmp(name, \"" << **i << "\") == 0) {" << std::endl << "\t\tstruct " << **i << "_sf *sf = malloc(sizeof(" "struct " << **i << "_sf));" << std::endl << "\t\tassert(sf != NULL);" << std::endl << "\t\tsf->static_parent = NULL;" << std::endl << "\t\tsf->kernel = kernel;" << std::endl << "\t\t" << **i << "(sf);" << std::endl << "\t\treturn 0;" << std::endl << "\t}" << std::endl; } this->dst << "\treturn -1;" << std::endl << "}" << std::endl; } }; /* namespace intermediate */ fauhdlc-20130704/intermediate/visitor/LookupSymbols.hpp0000664000175000017500000000531511461564704022522 0ustar potyrapotyra/* $Id: LookupSymbols.hpp 5047 2010-10-26 14:46:28Z potyra $ * * Lookup Symbols (currently only References) and annotate them with the * corresponding Data nodes. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LOOKUP_SYMBOLS_HPP_INCLUDED #define __LOOKUP_SYMBOLS_HPP_INCLUDED #include "intermediate/visitor/StandardTraversal.hpp" #include #include namespace intermediate { //! Lookup and resolve symbols in intermediate code. /** This visitor can resolve Symbols in the intermediate code. * Currently it looks up References. */ class LookupSymbols : public StandardTraversal { public: // c'tor LookupSymbols() : currentContainer(NULL) {} private: //! visit a CodeContainer node /** @param node node that gets visited. */ virtual void visit(CodeContainer &node); //! visit a Reference node /** @param node node that gets visited. */ virtual void visit(Reference &node); //! visit a SetParam node /** @param node node that gets visited. */ virtual void visit(SetParam &node); //! visit a Call node /** @param node node that gets visited. */ virtual void visit(Call &node); //! visit a Proc node /** @param node node that gets visited. */ virtual void visit(Proc &node); //! find the target container of a Call or Proc opcode. /** @param name look for a container with this name * @return target container or NULL if not found. */ const CodeContainer *findCallee(const std::string &name) const; //! find the Data definition of a Symbol. /** @param name search for symbol Name. * @return corresponding Data definition. * @todo this implementation is very simple and * should be optimized for speed. */ Data *findSymbol(const std::string &name) const; //! currently processed CodeContainer const CodeContainer *currentContainer; /* ----------------- Nested class: CompareData ----------------- */ //! subclass implementing a comparison of a Data object with a string class CompareData { public: //! c'tor /** @param n Name that should match the comparison. */ CompareData(const std::string &n) : name(n) {} //! Predicate that matches if the string is equal to the name /** @param d Data object that should get compared. * @return true if the name of the data object is the same as * our name, false otherwise. */ bool operator ()(const Data *d) const; private: //! name to match const std::string &name; }; }; }; /* namespace intermediate */ #endif /* __LOOKUP_SYMBOLS_HPP_INCLUDED */ fauhdlc-20130704/intermediate/visitor/Visitor.hpp0000664000175000017500000001331511460263314021326 0ustar potyrapotyra/* $Id: Visitor.hpp 5004 2010-10-22 10:26:20Z potyra $ * * Visitor (intermediate code). Abstract base class for visitors. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ // namespace collision #ifndef __INTERMEDIATE_VISITOR_HPP_INCLUDED #define __INTERMEDIATE_VISITOR_HPP_INCLUDED namespace intermediate { /* forward declaration of classes */ class CodeContainer; class BeginTransfer; class EndTransfer; class GetParam; class SetParam; class Connect; class Mov; class Je; class Jne; class Jb; class Jbe; class Jmp; class Label; class Abort; class Add; class Sub; class IMul; class Div; class Call; class Return; class Proc; class Update; class GetSig; class GetSimTime; class ROffset; class AOffset; class Suspend; class WakeOn; class WakeAt; class Log; class Reference; class Register; class ImmediateOperand; class IndirectOperand; class Data; class TypeElement; class Type; class Node; //! Generic interface for intermediate code vistitors. /** This is an abstract base class for all intermediate code visitors. */ class Visitor { public: //! virtual dummy d'tor virtual ~Visitor() {} //! visit a CodeContainer node /** @param node node that gets visited. */ virtual void visit(CodeContainer &node) = 0; //! visit a BeginTransfer node /** @param node node that gets visited. */ virtual void visit(BeginTransfer &node) = 0; //! visit an EndTransfer node /** @param node node that gets visited. */ virtual void visit(EndTransfer &node) = 0; //! visit a SetParam node /** @param node node that gets visited. */ virtual void visit(SetParam &node) = 0; //! visit a GetParam node /** @param node node that gets visited. */ virtual void visit(GetParam &node) = 0; //! visit a Connect node /** @param node node that gets visited. */ virtual void visit(Connect &node) = 0; //! visit a Mov node /** @param node node that gets visited. */ virtual void visit(Mov &node) = 0; //! visit a Je node /** @param node node that gets visited. */ virtual void visit(Je &node) = 0; //! visit a Jne node /** @param node node that gets visited. */ virtual void visit(Jne &node) = 0; //! visit a Jb node /** @param node node that gets visited. */ virtual void visit(Jb &node) = 0; //! visit a Jbe node /** @param node node that gets visited. */ virtual void visit(Jbe &node) = 0; //! visit a Jmp node /** @param node node that gets visited. */ virtual void visit(Jmp &node) = 0; //! visit a Label node /** @param node node that gets visited. */ virtual void visit(Label &node) = 0; //! visit an Abort node /** @param node node that gets visited. */ virtual void visit(Abort &node) = 0; //! visit an Add node /** @param node node that gets visited. */ virtual void visit(Add &node) = 0; //! visit an Sub node /** @param node node that gets visited. */ virtual void visit(Sub &node) = 0; //! visit an IMul node /** @param node node that gets visited. */ virtual void visit(IMul &node) = 0; //! visit a Div node /** @param node node that gets visited. */ virtual void visit(Div &node) = 0; //! visit a Call node /** @param node node that gets visited. */ virtual void visit(Call &node) = 0; //! visit a Return node /** @param node node that gets visited. */ virtual void visit(Return &node) = 0; //! visit a Proc node /** @param node node that gets visited. */ virtual void visit(Proc &node) = 0; //! visit an Update node /** @param node node that gets visited. */ virtual void visit(Update &node) = 0; //! visit a GetSig node /** @param node node that gets visited. */ virtual void visit(GetSig &node) = 0; //! visit a GetSimTime node /** @param node node that gets visited. */ virtual void visit(GetSimTime &node) = 0; //! visit a ROffset node /** @param node node that gets visited. */ virtual void visit(ROffset &node) = 0; //! visit an AOffset node /** @param node node that gets visited. */ virtual void visit(AOffset &node) = 0; //! visit a Suspend node /** @param node node that gets visited. */ virtual void visit(Suspend &node) = 0; //! visit a WakeOn node /** @param node node that gets visited. */ virtual void visit(WakeOn &node) = 0; //! visit a WakeAt node /** @param node node that gets visited. */ virtual void visit(WakeAt &node) = 0; //! visit a Log node /** @param node node that gets visited. */ virtual void visit(Log &node) = 0; //! visit an ImmediateOperand node /** @param node node that gets visited. */ virtual void visit(ImmediateOperand &node) = 0; //! visit an IndirectOperand node /** @param node node that gets visited. */ virtual void visit(IndirectOperand &node) = 0; //! visit a Reference node /** @param node node that gets visited. */ virtual void visit(Reference &node) = 0; //! visit a Register node /** @param node node that gets visited. */ virtual void visit(Register &node) = 0; //! visit a Data node /** @param node node that gets visited. */ virtual void visit(Data &node) = 0; //! visit a TypeElement node /** @param node node that gets visited. */ virtual void visit(TypeElement &node) = 0; //! visit a Type node /** @param node node that gets visited. */ virtual void visit(Type &node) = 0; protected: //! Travers a list of nodes. /** Traverse the the list l. * @param l list to traverse. Must be of any type that supports * a forward const_iterator. */ template void listTraverse(T &l); }; }; /* namespace intermediate */ #include "intermediate/visitor/Visitor.tpp" #endif /* __VISITOR_HPP_INCLUDED */ fauhdlc-20130704/intermediate/visitor/GenCCode.hpp0000664000175000017500000001652311461520162021300 0ustar potyrapotyra/* $Id: GenCCode.hpp 5037 2010-10-26 09:33:38Z potyra $ * * Generate C-Code from intermediate Code. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GEN_CCODE_HPP_INCLUDED #define __GEN_CCODE_HPP_INCLUDED #include "intermediate/visitor/Visitor.hpp" #include "intermediate/operands/RegisterFactory.hpp" #include namespace intermediate { //! generate C code from intermediate representation /** This visitor can be used to transform the intermediate * representation into C-code. */ class GenCCode : public Visitor { public: //! c'tor /** @param destination destination target stream, to * which code will get written to. */ GenCCode(std::ostream &destination); private: //! visit a CodeContainer node /** @param node node that gets visited. */ virtual void visit(CodeContainer &node); //! visit a ImmediateOperand node /** @param node node that gets visited. */ virtual void visit(ImmediateOperand &node); //! visit a BeginTransfer node /** @param node node that gets visited. */ virtual void visit(BeginTransfer &node); //! visit an EndTransfer node /** @param node node that gets visited. */ virtual void visit(EndTransfer &node); //! visit a SetParam node /** @param node node that gets visited. */ virtual void visit(SetParam &node); //! visit a GetParam node /** @param node node that gets visited. */ virtual void visit(GetParam &node); //! visit a Connect node /** @param node node that gets visited. */ virtual void visit(Connect &node); //! visit a Mov node /** @param node node that gets visited. */ virtual void visit(Mov &node); //! visit a Je node /** @param node node that gets visited. */ virtual void visit(Je &node); //! visit a Jbe node /** @param node node that gets visited. */ virtual void visit(Jbe &node); //! visit a Jne node /** @param node node that gets visited. */ virtual void visit(Jne &node); //! visit a Jb node /** @param node node that gets visited. */ virtual void visit(Jb &node); //! visit a Jmp node /** @param node node that gets visited. */ virtual void visit(Jmp &node); //! visit a Label node /** @param node node that gets visited. */ virtual void visit(Label &node); //! visit an Abort node /** @param node node that gets visited. */ virtual void visit(Abort &node); //! visit an Add node /** @param node node that gets visited. */ virtual void visit(Add &node); //! visit a Sub node /** @param node node that gets visited. */ virtual void visit(Sub &node); //! visit a Call node /** @param node node that gets visited. */ virtual void visit(Call &node); //! visit a Return node /** @param node node that gets visited. */ virtual void visit(Return &node); //! visit a Proc node /** @param node node that gets visited. */ virtual void visit(Proc &node); //! visit an Update node /** @param node node that gets visited. */ virtual void visit(Update &node); //! visit a GetSig node /** @param node node that gets visited. */ virtual void visit(GetSig &node); //! visit a GetSimTime node /** @param node node that gets visited. */ virtual void visit(GetSimTime &node); //! visit an IMul node /** @param node node that gets visited. */ virtual void visit(IMul &node); //! visit a Div node /** @param node node that gets visited. */ virtual void visit(Div &node); //! visit an ROffset node /** @param node node that gets visited. */ virtual void visit(ROffset &node); //! visit an AOffset node /** @param node node that gets visited. */ virtual void visit(AOffset &node); //! visit a Suspend node /** @param node node that gets visited. */ virtual void visit(Suspend &node); //! visit a WakeOn node /** @param node node that gets visited. */ virtual void visit(WakeOn &node); //! visit a WakeAt node /** @param node node that gets visited. */ virtual void visit(WakeAt &node); //! visit a Log node /** @param node node that gets visited. */ virtual void visit(Log &node); //! visit an IndirectOperand node /** @param node node that gets visited. */ virtual void visit(IndirectOperand &node); //! visit a Reference node /** @param node node that gets visited. */ virtual void visit(Reference &node); //! visit a Register node /** @param node node that gets visited. */ virtual void visit(Register &node); //! visit a Data node /** @param node node that gets visited. */ virtual void visit(Data &node); //! visit a TypeElement node /** @param node node that gets visited. */ virtual void visit(TypeElement &node); //! visit a Type node /** @param node node that gets visited. */ virtual void visit(Type &node); //! process a conditional jmp /** @param node conditional jump opcode. * @oaram op operator symbol to draw. */ template void processCondJmp(T &node, const char *op); //! process an arithmetic node. /** @param node arithmetic node * @param op operator symbol to draw. */ template void processArith(T &node, const char *op); //! process a record type /** @param node record type to process */ void processRecord(Type &node); //! process an array type /** @param node array type to process */ void processArray(Type &node); //! process a record type element /** @param node type element of a record type to process. * @param number element number. */ void processRecordElement(TypeElement &node, unsigned int number); //! generate variables for virtual Registers of a CodeContainer /** @param regFab RegisterFactory instance of the CodeContainer, * which keeps track of the virtual registers associated * with the container. */ void genRegisters(const RegisterFactory ®Fab); //! create statements to initialize data and signals /** @param container Code container in question. */ void initializeContainerData(const CodeContainer &container); //! create statements to initializie one data element. /** @param element data element in question. */ void initializeData(const Data &data); //! create the initializer for a variable /** @param data Variable declaration in question. */ void createVariable(const Data &data); //! create a driver /** @param data Driver declaration. */ void createDriver (const Data &data); //! create a signal /** @param data Signal declaration. */ void createSignal (const Data &data); //! put an OpType to this->dst /** @param t print it on this->dst. */ void putOpType(const enum OpType t); //! chain stack frames. /** @param callee Reference to the callee */ void chainStackFrames(const Reference &callee); //! create the prelude (includes etc.). void prelude(void); //! create the final function that maps vhdl names to function calls /* FIXME not yet used */ void finale(void); //! stream to put nodes to. std::ostream &dst; //! nesting level of current code container. unsigned int nestingLevel; //! list of functions that can be called by name /** currently the functions are restricted to those without * parameters. */ std::list funcs; //! add the finale? bool addFinale; }; }; /* namespace intermediate */ #endif /* __GEN_CCODE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/visitor/LookupSymbols.cpp0000664000175000017500000000601711461571106022507 0ustar potyrapotyra/* $Id: LookupSymbols.cpp 5049 2010-10-26 15:22:46Z potyra $ * * Lookup Symbols (currently only References) and annotate them with the * corresponding Data nodes. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include "intermediate/visitor/LookupSymbols.hpp" #include "intermediate/operands/Reference.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/container/CodeContainer.hpp" #include "intermediate/opcodes/SetParam.hpp" #include "intermediate/opcodes/Call.hpp" #include "intermediate/opcodes/Proc.hpp" namespace intermediate { void LookupSymbols::visit(CodeContainer &node) { this->currentContainer = &node; this->listTraverse(node.typeDefinitions); this->listTraverse(node.transferData); this->listTraverse(node.stackData); this->listTraverse(node.children); this->currentContainer = &node; this->listTraverse(node.code); } void LookupSymbols::visit(Reference &node) { const Data *d = this->findSymbol(node.name); node.associatedData = d; } void LookupSymbols::visit(SetParam &node) { node.src->accept(*this); // don't traverse to dst (yet?). It's located in the // transfer segment of a container on the same level // as the currently processed container. // Lookup would need to be adjusted for it. } void LookupSymbols::visit(Call &node) { assert(node.dst != NULL); node.dst->associatedContainer = this->findCallee(node.dst->name); } void LookupSymbols::visit(Proc &node) { assert(node.dst != NULL); node.dst->associatedContainer = this->findCallee(node.dst->name); } const CodeContainer * LookupSymbols::findCallee(const std::string &name) const { // Callee can be a direct child, or anywhere in the surrounding // containers. const CodeContainer *c = this->currentContainer; while (c != NULL) { for (std::list::const_iterator i = c->children.begin(); i != c->children.end(); i++) { if ((*i)->name == name) { return *i; } } if (c->name == name) { return c; } c = c->staticParent; } return NULL; } Data * LookupSymbols::findSymbol(const std::string &name) const { const CodeContainer *c = this->currentContainer; const CompareData cd = CompareData(name); while (c != NULL) { std::list::const_iterator needle = std::find_if( c->stackData.begin(), c->stackData.end(), cd); if (needle != c->stackData.end()) { return *needle; } needle = std::find_if( c->transferData.begin(), c->transferData.end(), cd); if (needle != c->transferData.end()) { return *needle; } c = c->staticParent; } return NULL; } /* ------------------- Nested class: CompareData ------------------- */ bool LookupSymbols::CompareData::operator ()(const Data *d) const { if (d == NULL) { return false; } return d->name == this->name; } }; /* namespace intermediate */ fauhdlc-20130704/intermediate/visitor/PrintCode.cpp0000664000175000017500000002770211460272251021556 0ustar potyrapotyra/* $Id: PrintCode.cpp 5008 2010-10-22 11:25:29Z potyra $ * * Print intermediate code to stream. * * Copyright (C) 2008-2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "intermediate/visitor/PrintCode.hpp" #include #include "intermediate/opcodes/Connect.hpp" #include "intermediate/opcodes/Je.hpp" #include "intermediate/opcodes/Jne.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Jbe.hpp" #include "intermediate/opcodes/Jmp.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Abort.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/opcodes/IMul.hpp" #include "intermediate/opcodes/Div.hpp" #include "intermediate/opcodes/Call.hpp" #include "intermediate/opcodes/Return.hpp" #include "intermediate/opcodes/Proc.hpp" #include "intermediate/opcodes/Update.hpp" #include "intermediate/opcodes/GetSig.hpp" #include "intermediate/opcodes/GetSimTime.hpp" #include "intermediate/opcodes/ROffset.hpp" #include "intermediate/opcodes/AOffset.hpp" #include "intermediate/opcodes/Suspend.hpp" #include "intermediate/opcodes/WakeOn.hpp" #include "intermediate/opcodes/WakeAt.hpp" #include "intermediate/opcodes/Log.hpp" #include "intermediate/opcodes/BeginTransfer.hpp" #include "intermediate/opcodes/EndTransfer.hpp" #include "intermediate/opcodes/SetParam.hpp" #include "intermediate/opcodes/GetParam.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/operands/IndirectOperand.hpp" #include "intermediate/operands/Reference.hpp" #include "intermediate/operands/Register.hpp" #include "intermediate/container/CodeContainer.hpp" #include "intermediate/container/Label.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/container/TypeElement.hpp" #include "intermediate/container/Type.hpp" namespace intermediate { PrintCode::PrintCode(std::ostream &destination) : dst(destination) { } void PrintCode::visit(CodeContainer &node) { this->dst << this->nest << "CONTAINER " << node.name << std::endl; this->dst << this->nest << ".REGISTERS " << node.getNumUsedRegs() << std::endl; if (! node.typeDefinitions.empty()) { this->dst << this->nest << ".TYPES" << std::endl; this->listTraverse(node.typeDefinitions); } if (! node.transferData.empty()) { this->dst << this->nest << ".TRANSFER" << std::endl; this->listTraverse(node.transferData); } if (! node.stackData.empty()) { this->dst << this->nest << ".STACK" << std::endl; this->listTraverse(node.stackData); } this->dst << std::endl; ++this->nest; this->listTraverse(node.children); --this->nest; if (! node.code.empty()) { this->dst << this->nest << ".TEXT" << std::endl; this->listTraverse(node.code); } this->dst << this->nest << "END CONTAINER " << node.name << ';' << std::endl << std::endl; } void PrintCode::visit(ImmediateOperand &node) { switch(node.type) { case OP_TYPE_REAL: this->dst << '$' << node.rValue << 'F'; break; case OP_TYPE_INTEGER: this->dst << '$' << node.iValue << 'L'; break; case OP_TYPE_POINTER: // illegal adressing mode: immediate pointer assert(false); break; } } void PrintCode::visit(BeginTransfer &node) { this->dst << this->nest << "\tBEGINTR\t"; node.src->accept(*this); this->dst << ", "; node.comp->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(EndTransfer &node) { this->dst << this->nest << "\tENDTR\t"; node.src->accept(*this); this->dst << ", "; node.cleanupStack->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(SetParam &node) { this->dst << this->nest << "\tSETPARM\t"; node.src->accept(*this); this->dst << ", "; node.container->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(GetParam &node) { this->dst << this->nest << "\tGETPARM\t"; node.src->accept(*this); this->dst << ", "; node.container->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Connect &node) { this->dst << this->nest << "\tCONNECT\t"; node.driver->accept(*this); this->dst << ", "; node.signal->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Mov &node) { this->dst << this->nest << "\tMOV\t"; node.src->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Je &node) { this->dst << this->nest << "\tJE\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", @" << node.trg->name; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Jbe &node) { this->dst << this->nest << "\tJBE\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", @" << node.trg->name; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Jne &node) { this->dst << this->nest << "\tJNE\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", @" << node.trg->name; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Jb &node) { this->dst << this->nest << "\tJB\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", @" << node.trg->name; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Jmp &node) { this->dst << this->nest << "\tJMP\t@" << node.trg->name ; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Label &node) { this->dst << this->nest << node.name << ':'; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Add &node) { this->dst << this->nest << "\tADD\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Abort &node) { this->dst << this->nest << "\tABORT\t"; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Sub &node) { this->dst << this->nest << "\tSUB\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Call &node) { assert(node.dst != NULL); this->dst << this->nest << "\tCALL\t"; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Return &node) { this->dst << this->nest << "\tRETURN"; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Proc &node) { assert(node.dst != NULL); this->dst << this->nest << "\tPROC\t"; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Update &node) { this->dst << this->nest << "\tUPDATE\t"; node.src->accept(*this); this->dst << ", "; node.delay->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(GetSig &node) { this->dst << this->nest << "\tGETSIG\t"; node.src->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(GetSimTime &node) { this->dst << this->nest << "\tGETTIME\t"; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(IMul &node) { this->dst << this->nest << "\tIMUL\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Div &node) { this->dst << this->nest << "\tDIV\t"; node.left->accept(*this); this->dst << ", "; node.right->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(ROffset &node) { this->dst << this->nest << "\tROFFSET\t"; node.base->accept(*this); this->dst << ", "; this->dst << node.rtype->name << "->"; node.offset->accept(*this); this->dst << ", "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(AOffset &node) { this->dst << this->nest << "\tAOFFSET\t"; node.base->accept(*this); this->dst << ", " << node.atype->name << "["; node.offset->accept(*this); this->dst << "], "; node.dst->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Suspend &node) { this->dst << this->nest << "\tSUSPEND"; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(WakeOn &node) { this->dst << this->nest << "\tWAKEON\t"; node.src->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(WakeAt &node) { this->dst << this->nest << "\tWAKEAT\t"; node.wakeTime->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(Log &node) { this->dst << this->nest << "\tLOG\t"; node.lvl->accept(*this); this->dst << ", "; node.c->accept(*this); this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(IndirectOperand &node) { this->putOpType(node.type); this->dst << '('; node.src->accept(*this); this->dst << ')'; } void PrintCode::visit(Reference &node) { this->dst << '"' << node.name << '"'; } void PrintCode::visit(Register &node) { this->putOpType(node.type); this->dst << "%reg_" << node.num; } void PrintCode::visit(Data &node) { this->dst << this->nest << "DATA\t"; if (node.resolver) { this->dst << "RESOLVEDBY " << *node.resolver << " "; } switch (node.storage) { case STORAGE_TYPE_VARIABLE: this->dst << "VARIABLE\t"; break; case STORAGE_TYPE_DRIVER: this->dst << "DRIVER\t"; break; case STORAGE_TYPE_SIGNAL: this->dst << "SIGNAL\t"; break; } this->dst << node.name << "\t"; if (node.dataType != NULL) { node.dataType->accept(*this); } this->dst << ';'; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::visit(TypeElement &node) { this->dst << node.name; if (node.ubound != 1) { this->dst << '[' << node.ubound << ']'; } if (! node.init.empty()) { this->dst << " := "; } for (std::list::iterator i = node.init.begin(); i != node.init.end(); i++) { if (i != node.init.begin()) { this->dst << " "; } (*i)->accept(*this); } this->putAnnotation(node); } void PrintCode::visit(Type &node) { this->dst << this->nest << "TYPE " << node.name << " is " << std::endl << this->nest << "\t\t"; for (std::list::iterator i = node.elements.begin(); i != node.elements.end(); i++) { if (i != node.elements.begin()) { this->dst << ',' << std::endl << this->nest << "\t\t"; } (*i)->accept(*this); } this->dst << ';'; this->putAnnotation(node); this->dst << std::endl; } void PrintCode::putAnnotation(const Node &node) const { if (node.intAnnotations.empty() && node.strAnnotations.empty()) { return; } this->dst << " { "; for (std::list::const_iterator i = node.intAnnotations.begin(); i != node.intAnnotations.end(); i++) { this->dst << i->first << "=" << i->second << " "; } for (std::list::const_iterator i = node.strAnnotations.begin(); i != node.strAnnotations.end(); i++) { this->dst << i->first << "=\"" << i->second << "\" "; } this->dst << "}"; } void PrintCode::putOpType(const enum OpType t) { switch(t) { case OP_TYPE_INTEGER: this->dst << 'i'; break; case OP_TYPE_REAL: this->dst << 'r'; break; case OP_TYPE_POINTER: this->dst << 'p'; break; } } std::ostream & operator <<(std::ostream &stream, const PrintCode::Nesting &n) { n.put(stream); return stream; } }; /* namespace ast */ fauhdlc-20130704/intermediate/visitor/StandardTraversal.cpp0000664000175000017500000001345511460271756023324 0ustar potyrapotyra/* $Id: StandardTraversal.cpp 5007 2010-10-22 11:22:22Z potyra $ * * Perform a standard traversal on the intermediate code. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "intermediate/visitor/StandardTraversal.hpp" #include "intermediate/opcodes/Connect.hpp" #include "intermediate/opcodes/Je.hpp" #include "intermediate/opcodes/Jne.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Jbe.hpp" #include "intermediate/opcodes/Jmp.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Abort.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/opcodes/IMul.hpp" #include "intermediate/opcodes/Div.hpp" #include "intermediate/opcodes/Call.hpp" #include "intermediate/opcodes/Return.hpp" #include "intermediate/opcodes/Proc.hpp" #include "intermediate/opcodes/Update.hpp" #include "intermediate/opcodes/GetSig.hpp" #include "intermediate/opcodes/GetSimTime.hpp" #include "intermediate/opcodes/ROffset.hpp" #include "intermediate/opcodes/AOffset.hpp" #include "intermediate/opcodes/Suspend.hpp" #include "intermediate/opcodes/WakeOn.hpp" #include "intermediate/opcodes/WakeAt.hpp" #include "intermediate/opcodes/Log.hpp" #include "intermediate/opcodes/BeginTransfer.hpp" #include "intermediate/opcodes/EndTransfer.hpp" #include "intermediate/opcodes/SetParam.hpp" #include "intermediate/opcodes/GetParam.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/operands/IndirectOperand.hpp" #include "intermediate/operands/Reference.hpp" #include "intermediate/operands/Register.hpp" #include "intermediate/container/CodeContainer.hpp" #include "intermediate/container/Label.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/container/TypeElement.hpp" #include "intermediate/container/Type.hpp" namespace intermediate { StandardTraversal::StandardTraversal() { } void StandardTraversal::visit(CodeContainer &node) { this->listTraverse(node.typeDefinitions); this->listTraverse(node.transferData); this->listTraverse(node.stackData); this->listTraverse(node.children); this->listTraverse(node.code); } void StandardTraversal::visit(ImmediateOperand &node) { // leaf node } void StandardTraversal::visit(BeginTransfer &node) { node.src->accept(*this); node.comp->accept(*this); } void StandardTraversal::visit(EndTransfer &node) { node.src->accept(*this); node.cleanupStack->accept(*this); } void StandardTraversal::visit(SetParam &node) { node.src->accept(*this); node.container->accept(*this); node.dst->accept(*this); } void StandardTraversal::visit(GetParam &node) { node.src->accept(*this); node.container->accept(*this); node.dst->accept(*this); } void StandardTraversal::visit(Connect &node) { node.driver->accept(*this); node.signal->accept(*this); } void StandardTraversal::visit(Mov &node) { node.dst->accept(*this); node.src->accept(*this); } void StandardTraversal::visit(Je &node) { this->traverseCondJmp(node); } void StandardTraversal::visit(Jbe &node) { this->traverseCondJmp(node); } void StandardTraversal::visit(Jne &node) { this->traverseCondJmp(node); } void StandardTraversal::visit(Jb &node) { this->traverseCondJmp(node); } void StandardTraversal::visit(Jmp &node) { node.trg->accept(*this); } void StandardTraversal::visit(Label &node) { // leaf node } void StandardTraversal::visit(Add &node) { this->traverseBinOp(node); } void StandardTraversal::visit(Abort &node) { // leaf node } void StandardTraversal::visit(Sub &node) { this->traverseBinOp(node); } void StandardTraversal::visit(Call &node) { node.dst->accept(*this); } void StandardTraversal::visit(Return &node) { // leaf node } void StandardTraversal::visit(Proc &node) { node.dst->accept(*this); } void StandardTraversal::visit(Update &node) { node.src->accept(*this); node.delay->accept(*this); node.dst->accept(*this); } void StandardTraversal::visit(GetSig &node) { node.src->accept(*this); node.dst->accept(*this); } void StandardTraversal::visit(GetSimTime &node) { node.dst->accept(*this); } void StandardTraversal::visit(IMul &node) { this->traverseBinOp(node); } void StandardTraversal::visit(Div &node) { this->traverseBinOp(node); } void StandardTraversal::visit(ROffset &node) { node.base->accept(*this); node.offset->accept(*this); node.rtype->accept(*this); node.dst->accept(*this); } void StandardTraversal::visit(AOffset &node) { node.base->accept(*this); node.offset->accept(*this); node.atype->accept(*this); node.dst->accept(*this); } void StandardTraversal::visit(Suspend &node) { // leaf node } void StandardTraversal::visit(WakeOn &node) { node.src->accept(*this); } void StandardTraversal::visit(WakeAt &node) { node.wakeTime->accept(*this); } void StandardTraversal::visit(Log &node) { node.lvl->accept(*this); node.c->accept(*this); } void StandardTraversal::visit(IndirectOperand &node) { node.src->accept(*this); } void StandardTraversal::visit(Reference &node) { // leaf node } void StandardTraversal::visit(Register &node) { // leaf node } void StandardTraversal::visit(Data &node) { node.dataType->accept(*this); } void StandardTraversal::visit(Type &node) { this->listTraverse(node.elements); } void StandardTraversal::visit(TypeElement &node) { this->listTraverse(node.init); } template void StandardTraversal::traverseCondJmp(T &node) { node.left->accept(*this); node.right->accept(*this); node.trg->accept(*this); } template void StandardTraversal::traverseBinOp(T &node) { node.left->accept(*this); node.right->accept(*this); node.dst->accept(*this); } }; /* namespace intermediate */ fauhdlc-20130704/intermediate/visitor/PrintCode.hpp0000664000175000017500000001424211460053342021554 0ustar potyrapotyra/* $Id: PrintCode.hpp 4992 2010-10-21 15:06:10Z potyra $ * * Print intermediate code to stream. * * Copyright (C) 2008-2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PRINT_CODE_HPP #define __PRINT_CODE_HPP #include "intermediate/visitor/Visitor.hpp" #include "intermediate/operands/Operand.hpp" #include namespace intermediate { //! print out intermediate code /** This visitor can be used to print out intermediate code. * It's main use is to debug the intermediate code. The format * how the intermediate code looks like, may still change. * * Format conventions: * There is no opcode, which can accept more than three operands. * In case there is a destination operand, which will be the result * of one or more source operands, it will always be the rightmost * operand. */ class PrintCode : public Visitor { public: //! c'tor /** @param destination target stream, to which code will get written * to */ PrintCode(std::ostream &destination); private: //! visit a CodeContainer node /** @param node node that gets visited. */ virtual void visit(CodeContainer &node); //! visit a ImmediateOperand node /** @param node node that gets visited. */ virtual void visit(ImmediateOperand &node); //! visit a BeginTransfer node /** @param node node that gets visited. */ virtual void visit(BeginTransfer &node); //! visit an EndTransfer node /** @param node node that gets visited. */ virtual void visit(EndTransfer &node); //! visit a SetParam node /** @param node node that gets visited. */ virtual void visit(SetParam &node); //! visit a GetParam node /** @param node node that gets visited. */ virtual void visit(GetParam &node); //! visit a Connect node /** @param node node that gets visited. */ virtual void visit(Connect &node); //! visit a Mov node /** @param node node that gets visited. */ virtual void visit(Mov &node); //! visit a Je node /** @param node node that gets visited. */ virtual void visit(Je &node); //! visit a Jbe node /** @param node node that gets visited. */ virtual void visit(Jbe &node); //! visit a Jne node /** @param node node that gets visited. */ virtual void visit(Jne &node); //! visit a Jb node /** @param node node that gets visited. */ virtual void visit(Jb &node); //! visit a Jmp node /** @param node node that gets visited. */ virtual void visit(Jmp &node); //! visit a Label node /** @param node node that gets visited. */ virtual void visit(Label &node); //! visit an Abort node /** @param node node that gets visited. */ virtual void visit(Abort &node); //! visit an Add node /** @param node node that gets visited. */ virtual void visit(Add &node); //! visit a Sub node /** @param node node that gets visited. */ virtual void visit(Sub &node); //! visit a Call node /** @param node node that gets visited. */ virtual void visit(Call &node); //! visit a Return node /** @param node node that gets visited. */ virtual void visit(Return &node); //! visit a Proc node /** @param node node that gets visited. */ virtual void visit(Proc &node); //! visit an Update node /** @param node node that gets visited. */ virtual void visit(Update &node); //! visit a GetSig node /** @param node node that gets visited. */ virtual void visit(GetSig &node); //! visit a GetSimTime node /** @param node node that gets visited. */ virtual void visit(GetSimTime &node); //! visit an IMul node /** @param node node that gets visited. */ virtual void visit(IMul &node); //! visit a Div node /** @param node node that gets visited. */ virtual void visit(Div &node); //! visit an ROffset node /** @param node node that gets visited. */ virtual void visit(ROffset &node); //! visit an AOffset node /** @param node node that gets visited. */ virtual void visit(AOffset &node); //! visit a Suspend node /** @param node node that gets visited. */ virtual void visit(Suspend &node); //! visit a WakeOn node /** @param node node that gets visited. */ virtual void visit(WakeOn &node); //! visit a WakeAt node /** @param node node that gets visited. */ virtual void visit(WakeAt &node); //! visit a Log node /** @param node node that gets visited. */ virtual void visit(Log &node); //! visit an IndirectOperand node /** @param node node that gets visited. */ virtual void visit(IndirectOperand &node); //! visit a Reference node /** @param node node that gets visited. */ virtual void visit(Reference &node); //! visit a Register node /** @param node node that gets visited. */ virtual void visit(Register &node); //! visit a Data node /** @param node node that gets visited. */ virtual void visit(Data &node); //! visit a TypeElement node /** @param node node that gets visited. */ virtual void visit(TypeElement &node); //! visit a Type node /** @param node node that gets visited. */ virtual void visit(Type &node); //! put the annotations to stream, if any. /** @param node intermediate code node in question. */ void putAnnotation(const Node &node) const; //! stream to put nodes to. std::ostream &dst; //! small class to support different levels of nesting. struct Nesting { public: Nesting() : level(0) {} void operator++(void) { this->level++; } void operator--(void) { this->level--; } void put(std::ostream &stream) const { for (unsigned int i = 0; i < this->level; i++) { stream << " "; } } private: unsigned int level; } nest; //! make sure that << can see class Nesting. friend std::ostream& operator<<(std::ostream &stream, const Nesting &n); //! print out OpType for intermediate code representation /** @param t print this to the stream this->dst */ void putOpType(const enum OpType t); }; //! overloaded operator for nesting. Must not be used outside of class. std::ostream & operator <<(std::ostream &stream, const PrintCode::Nesting &n); }; /* namespace intermediate */ #endif /* __PRINT_CODE_HPP */ fauhdlc-20130704/intermediate/visitor/StandardTraversal.hpp0000664000175000017500000001220711460270562023315 0ustar potyrapotyra/* $Id: StandardTraversal.hpp 5006 2010-10-22 11:11:46Z potyra $ * * Perform a standard traversal on the intermediate code. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __STANDARD_TRAVERSAL_HPP_INCLUDED #define __STANDARD_TRAVERSAL_HPP_INCLUDED #include "intermediate/visitor/Visitor.hpp" namespace intermediate { //! Perform a standard traversal on the intermediate code. /** This visitor will perform a standard traversal on the intermediate * code. Visitors, that are only interested in a subset of the nodes * can inherit from this visitor. */ class StandardTraversal : public Visitor { public: //! c'tor StandardTraversal(); protected: //! visit a CodeContainer node /** @param node node that gets visited. */ virtual void visit(CodeContainer &node); //! visit a ImmediateOperand node /** @param node node that gets visited. */ virtual void visit(ImmediateOperand &node); //! visit a BeginTransfer node /** @param node node that gets visited. */ virtual void visit(BeginTransfer &node); //! visit an EndTransfer node /** @param node node that gets visited. */ virtual void visit(EndTransfer &node); //! visit a SetParam node /** @param node node that gets visited. */ virtual void visit(SetParam &node); //! visit a GetParam node /** @param node node that gets visited. */ virtual void visit(GetParam &node); //! visit a Connect node /** @param node node that gets visited. */ virtual void visit(Connect &node); //! visit a Mov node /** @param node node that gets visited. */ virtual void visit(Mov &node); //! visit a Je node /** @param node node that gets visited. */ virtual void visit(Je &node); //! visit a Jbe node /** @param node node that gets visited. */ virtual void visit(Jbe &node); //! visit a Jne node /** @param node node that gets visited. */ virtual void visit(Jne &node); //! visit a Jb node /** @param node node that gets visited. */ virtual void visit(Jb &node); //! visit a Jmp node /** @param node node that gets visited. */ virtual void visit(Jmp &node); //! visit a Label node /** @param node node that gets visited. */ virtual void visit(Label &node); //! visit an Abort node /** @param node node that gets visited. */ virtual void visit(Abort &node); //! visit an Add node /** @param node node that gets visited. */ virtual void visit(Add &node); //! visit a Sub node /** @param node node that gets visited. */ virtual void visit(Sub &node); //! visit a Call node /** @param node node that gets visited. */ virtual void visit(Call &node); //! visit a Return node /** @param node node that gets visited. */ virtual void visit(Return &node); //! visit a Proc node /** @param node node that gets visited. */ virtual void visit(Proc &node); //! visit an Update node /** @param node node that gets visited. */ virtual void visit(Update &node); //! visit a GetSig node /** @param node node that gets visited. */ virtual void visit(GetSig &node); //! visit a GetSimTime node /** @param node node that gets visited. */ virtual void visit(GetSimTime &node); //! visit an IMul node /** @param node node that gets visited. */ virtual void visit(IMul &node); //! visit a Div node /** @param node node that gets visited. */ virtual void visit(Div &node); //! visit an ROffset node /** @param node node that gets visited. */ virtual void visit(ROffset &node); //! visit an AOffset node /** @param node node that gets visited. */ virtual void visit(AOffset &node); //! visit a Suspend node /** @param node node that gets visited. */ virtual void visit(Suspend &node); //! visit a WakeOn node /** @param node node that gets visited. */ virtual void visit(WakeOn &node); //! visit a WakeAt node /** @param node node that gets visited. */ virtual void visit(WakeAt &node); //! visit a Log node /** @param node node that gets visited. */ virtual void visit(Log &node); //! visit an IndirectOperand node /** @param node node that gets visited. */ virtual void visit(IndirectOperand &node); //! visit a Reference node /** @param node node that gets visited. */ virtual void visit(Reference &node); //! visit a Register node /** @param node node that gets visited. */ virtual void visit(Register &node); //! visit a Data node /** @param node node that gets visited. */ virtual void visit(Data &node); //! visit a TypeElement node /** @param node node that gets visited. */ virtual void visit(TypeElement &node); //! visit a Type node /** @param node node that gets visited. */ virtual void visit(Type &node); private: //! traverse a conditional jump /** @param node conditional jump node. */ template void traverseCondJmp(T &node); //! traverse a binary operator /** @param node binary operator. */ template void traverseBinOp(T &node); }; }; /* namespace intermediate */ #endif /* __STANDARD_TRAVERSAL_HPP_INCLUDED */ fauhdlc-20130704/intermediate/visitor/Visitor.tpp0000664000175000017500000000125311460263314021340 0ustar potyrapotyra/* $Id: Visitor.tpp 5004 2010-10-22 10:26:20Z potyra $ * vim:tabstop=8:shiftwidth=8:filetype=cpp:textwidth=72: * * Base class Visitor (intermediate code). Template implementations. * * Copyright (C) 2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ namespace intermediate { template void Visitor::listTraverse(T &l) { for (typename T::const_iterator i = l.begin(); i != l.end(); i++) { (*i)->accept(*this); } } }; /* namespace intermediate */ fauhdlc-20130704/intermediate/Node.hpp0000664000175000017500000000401611137610234017051 0ustar potyrapotyra/* $Id: Node.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Abstract base class for all intermediate code nodes. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NODE_HPP_INCLUDED #define __NODE_HPP_INCLUDED #include "intermediate/visitor/Visitor.hpp" #include "util/MiscUtil.hpp" #include "util/GarbageCollect.hpp" #include namespace intermediate { //! base class for all visitible intermediate classes. /** This class is an abstract base class for all intermediate * code classes, that can get visited. */ class Node : public util::GarbageCollect { public: //! c'tor Node() {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) = 0; //! shortcut type definition for integer annotations. typedef std::pair intAnnoT; //! shortcut type definition for string annotations. typedef std::pair strAnnoT; //! add an annotations in the form of name=int /** @param name name of the annotation * @param value integer value of the annotation */ void annotate(std::string name, int value) { this->intAnnotations.push_back(intAnnoT(name, value)); } //! add an annotations in the form of name="string" /** @param name name of the annotation * @param value string value of the annotation */ void annotate(std::string name, std::string value) { this->strAnnotations.push_back(strAnnoT(name, value)); } //! list of integer annotations std::list intAnnotations; //! list of string annotations std::list strAnnotations; protected: /** virtual dummy d'tor. */ virtual ~Node() {} }; }; /* namespace intermediate */ #endif /* __NODE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/operands/0000775000175000017500000000000012165333100017261 5ustar potyrapotyrafauhdlc-20130704/intermediate/operands/Operand.hpp0000664000175000017500000000201311460052233021360 0ustar potyrapotyra/* $Id: Operand.hpp 4991 2010-10-21 14:56:27Z potyra $ * * Copyright (C) 2008-2010 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __OPERAND_HPP_INCLUDED #define __OPERAND_HPP_INCLUDED #include "intermediate/Node.hpp" namespace intermediate { //! different types of operands enum OpType { //! an integer value (only immediate) OP_TYPE_INTEGER, //! a real value (only immediate) OP_TYPE_REAL, //! a pointer value (immediate or indirect, indirect & offset) OP_TYPE_POINTER }; //! one operand /** This class represents one operand for the intermediate code. */ class Operand : public Node { public: //! c'tor /** @param t operand type */ Operand(enum OpType t) : type(t) {} //! base type of the Operand enum OpType type; }; }; /* namespace intermediate */ #endif /* __OPERAND_HPP_INCLUDED */ fauhdlc-20130704/intermediate/operands/IndirectOperand.hpp0000664000175000017500000000306111137610234023050 0ustar potyrapotyra/* $Id: IndirectOperand.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __INDIRECT_OPERAND_HPP_INCLUDED #define __INDIRECT_OPERAND_HPP_INCLUDED #include "intermediate/operands/Operand.hpp" #include "intermediate/operands/Register.hpp" #include namespace intermediate { //! an indirect operand /** This class represents an indirect operand. This means, that the source may * only be of storage class pointer. When accessing an indirect operand, * the source pointer will get dereferenced. */ class IndirectOperand : public Operand { public: //! c'tor /** @param source source of the operand (register, name). * @param t width to use for deferentiation. */ IndirectOperand( Register *source, enum OpType t ) : Operand(t), src(source) { // can dereference only pointers! assert(source->type == OP_TYPE_POINTER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor &v) { v.visit(*this); } //! source of the operand. Register *src; protected: virtual ~IndirectOperand() { util::MiscUtil::terminate(this->src); } }; }; /* namespace intermediate */ #endif /* __INDIRECT_OPERAND_HPP_INCLUDED */ fauhdlc-20130704/intermediate/operands/Register.hpp0000664000175000017500000000235411457330422021571 0ustar potyrapotyra/* $Id: Register.hpp 4984 2010-10-19 14:54:10Z potyra $ * * Register: a virtual register in the intermediate code. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __REGISTER_HPP_INCLUDED #define __REGISTER_HPP_INCLUDED #include "intermediate/operands/Operand.hpp" namespace intermediate { //! one virtual register. /** This class represents a virtual register, with a given type. */ class Register : public Operand { private: friend class RegisterFactory; //! private c'tor, use RegisterFactory instead /** @param t type of the virtual register. * @param n number of the virtual register. */ Register(enum OpType t, size_t n) : Operand(t), num(n) {} public: //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor &v) { v.visit(*this); } //! unique number size_t num; }; }; /* namespace intermediate */ #endif /* __REGISTER_HPP_INCLUDED */ fauhdlc-20130704/intermediate/operands/ImmediateOperand.cpp0000664000175000017500000000214611137610234023203 0ustar potyrapotyra/* $Id: ImmediateOperand.cpp 4323 2009-01-27 13:48:12Z potyra $ * * ImmediateOperand: An operand with a value. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "intermediate/operands/ImmediateOperand.hpp" namespace intermediate { ImmediateOperand *ImmediateOperand::one = NULL; ImmediateOperand *ImmediateOperand::zero = NULL; ImmediateOperand * ImmediateOperand::getZero(void) { if (ImmediateOperand::zero == NULL) { ImmediateOperand::zero = new ImmediateOperand( static_cast(0)); return ImmediateOperand::zero; } return ImmediateOperand::zero; } ImmediateOperand * ImmediateOperand::getOne(void) { if (ImmediateOperand::one == NULL) { ImmediateOperand::one = new ImmediateOperand( static_cast(1)); return ImmediateOperand::one; } return ImmediateOperand::one; } }; /* namespace intermediate */ fauhdlc-20130704/intermediate/operands/RegisterFactory.cpp0000664000175000017500000000147711457330422023121 0ustar potyrapotyra/* $Id: RegisterFactory.cpp 4984 2010-10-19 14:54:10Z potyra $ * * RegisterFactory: create and keep track of virtual registers. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "intermediate/operands/RegisterFactory.hpp" #include "intermediate/operands/Register.hpp" namespace intermediate { Register * RegisterFactory::getReg(enum OpType type) { Register *ret = new Register(type, this->regTypes.size()); this->regTypes.push_back(type); return ret; } size_t RegisterFactory::getNumUsedRegs(void) const { return this->regTypes.size(); } }; /* namespace intermediate */ fauhdlc-20130704/intermediate/operands/ImmediateOperand.hpp0000664000175000017500000000344311137610234023211 0ustar potyrapotyra/* $Id: ImmediateOperand.hpp 4323 2009-01-27 13:48:12Z potyra $ * * ImmediateOperand: An operand with a value. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __IMMEDIATE_OPERAND_HPP_INCLUDED #define __IMMEDIATE_OPERAND_HPP_INCLUDED #include "frontend/ast/Types.hpp" #include "intermediate/operands/Operand.hpp" namespace intermediate { //! immediate operand. /** This class represents an immediate operand. This means, that the operand * must be a value (either int or real). */ class ImmediateOperand : public Operand { public: //! c'tor for const integer operands /** @param val universal_integer value */ ImmediateOperand( universal_integer val ) : Operand(OP_TYPE_INTEGER), iValue(val) {} //! c'tior for const real operands /** @param val universal_real value */ ImmediateOperand( universal_real val ) : Operand(OP_TYPE_REAL), rValue(val) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor &v) { v.visit(*this); } //! integer value universal_integer iValue; //! real value universal_real rValue; //! return the ImmediateOperand for zero. static ImmediateOperand * getZero(void); //! return the ImmediateOperand for one. static ImmediateOperand * getOne(void); private: //! universal integer 0. static ImmediateOperand *zero; //! universal integer 1. static ImmediateOperand *one; }; }; /* namespace intermediate */ #endif /* __IMMEDIATE_OPERAND_HPP_INCLUDED */ fauhdlc-20130704/intermediate/operands/RegisterFactory.hpp0000664000175000017500000000302611457331773023130 0ustar potyrapotyra/* $Id: RegisterFactory.hpp 4985 2010-10-19 15:06:35Z potyra $ * * RegisterFactory: create and keep track of virtual registers. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __REGISTER_FACTORY_HPP_INCLUDED #define __REGISTER_FACTORY_HPP_INCLUDED #include #include "intermediate/operands/Register.hpp" namespace intermediate { //FIXME nest class in CodeContainer //! create virtual register (operands). /** TODO keep better track of handed out vregs? */ class RegisterFactory { public: //! obtain the vector of register types. /** @return vector of register types. Do not fiddle with it! */ const std::vector& getRegTypes(void) const { return this->regTypes; } private: friend class CodeContainer; //! c'tor RegisterFactory() : regTypes(std::vector()) {} //! create a virtual Register. /** @param type type of the virtual register operand * @return newly created virtual register. */ Register * getReg(enum OpType type); /** return the number of created virtual registers. * @return number of created virtual registers. */ size_t getNumUsedRegs(void) const; //! vector containing the types of the Registers. std::vector regTypes; }; }; /* namespace intermediate */ #endif /* __REGISTER_FACTORY_HPP_INCLUDED */ fauhdlc-20130704/intermediate/operands/Reference.hpp0000664000175000017500000000317011461564704021707 0ustar potyrapotyra/* $Id: Reference.hpp 5047 2010-10-26 14:46:28Z potyra $ * * Reference: pointer to a symbol. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __REFERENCE_HPP_INCLUDED #define __REFERENCE_HPP_INCLUDED #include "intermediate/operands/Operand.hpp" #include namespace intermediate { //! Reference to a named entity /** The reference can refer to any named entity. Hence a Reference is * always a pointer. It's main use is for indirect addressing, though it * sometimes might make sense to also take the pointer for pointer * arithmetics. */ class Reference : public Operand { public: //! c'tor /** @param n referenced name */ Reference( std::string n ) : Operand(OP_TYPE_POINTER), name(n), associatedData(NULL), associatedContainer(NULL) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor &v) { v.visit(*this); } //! name of the variable or driver std::string name; //! Data entry to which this Reference refers to /** might be NULL, e.g. for References referring to * Containers or Types. */ const Data *associatedData; //! associated CodeContainer for Call and Proc opcodes. const CodeContainer *associatedContainer; }; }; /* namespace intermediate */ #endif /* __REFERENCE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/0000775000175000017500000000000012165333100017102 5ustar potyrapotyrafauhdlc-20130704/intermediate/opcodes/BeginTransfer.hpp0000664000175000017500000000374511137610234022361 0ustar potyrapotyra/* $Id: BeginTransfer.hpp 4323 2009-01-27 13:48:12Z potyra $ * * BeginTransfer: allocate space for transfer region. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __BEGIN_TRANSFER_HPP_INCLUDED #define __BEGIN_TRANSFER_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Reference.hpp" namespace intermediate { //! allocate space for transfer region. /** This opcode will allocate space for the named transfer region. * SetParam call after BeginTransfer will write into this allocated region. * * Read operands: src, comp * Write operands: no publicly visible operands. * * Operation: * Allocate space for the transfer section of component src at an * implementation defined location. * Use comp as name for current stack frame. */ class BeginTransfer : public OpCode { public: //! c'tor /** @param source reference to a component. * @param compName instance name of the component. */ BeginTransfer( Reference *source, Reference *compName) : src(source), comp(compName) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! references a component (denoting the transfer region of it) Reference *src; /** name of the instantiated component, in case the BeginTransfer * is used to call a component create function. Empty reference * otherwise. * Used so that the stack frames can denote unique instance names. */ Reference *comp; protected: virtual ~BeginTransfer() { util::MiscUtil::terminate(this->src); } }; }; /* namespace intermediate */ #endif /* __BEGIN_TRANSFER_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Connect.hpp0000664000175000017500000000305611137610234021214 0ustar potyrapotyra/* $Id: Connect.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Connect: Connect a driver to a signal. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONNECT_HPP_INCLUDED #define __CONNECT_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" namespace intermediate { //! Connect a driver to a signal. /** This class can be used to connect a driver to a given signal. * * Read operands: drv, sig * Write operands: None. * * Operation: * Call an external mechanism to connect the driver to the signal. */ class Connect : public OpCode { public: //! c'tor /** @param drv Operand referring to a driver pointer. * @param sig Operand referring to a signal pointer. */ Connect(Operand *drv, Operand *sig) : driver(drv), signal(sig) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! driver to connect. Operand *driver; //! signal the driver gets connected to. Operand *signal; protected: virtual ~Connect() { util::MiscUtil::terminate(this->driver); util::MiscUtil::terminate(this->signal); } }; }; /* namespace intermediate */ #endif /* __CONNECT_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/SetParam.hpp0000664000175000017500000000501511137610234021334 0ustar potyrapotyra/* $Id: SetParam.hpp 4323 2009-01-27 13:48:12Z potyra $ * * SetParam: Set a parameter in the transfer region. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SET_PARAM_HPP_INCLUDED #define __SET_PARAM_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Reference.hpp" namespace intermediate { //! Copy source to a slot in the transfer region of a container. /** This opcode will copy source to the transfer slot dst from container * container into the previously allocated region. * * Read Operands: src, cnt, dst * Write operands: no publicly visible operands. * * Operation: * copy src to the slot defined by cnt/dst. * * Errors: * SetParam must be evaluated after a corresponding BeginTransfer * statement in the same text segment before a corresponding * EndTransfer statement. * * The Reference to the container must match the Reference to * BeginTransfer. * * Hint: An implementation could allocate space on the stack for * BeginTransfer (where the size would match the size of the transfer * statement), SetParam could calculate the relative stack offset * by cnt/dest to the stack top and EndTransfer could deallocate the * space on the stack again. So SetParam w.o. BeginTransfer would * basically corrupt the current stack frame. */ class SetParam : public OpCode { public: //! c'tor /** @param source source operand * @param cnt Reference to the container * @param dest Reference to item in transfer segment of container. */ SetParam( Operand *source, Reference *cnt, Reference *dest ) : src(source), container(cnt), dst(dest) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! source operand Operand *src; //! referenced container Reference *container; //! item in transfer segment of referenced container Reference *dst; protected: virtual ~SetParam() { util::MiscUtil::terminate(this->src); util::MiscUtil::terminate(this->container); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __SET_PARAM_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/GetSig.hpp0000664000175000017500000000357211137610234021010 0ustar potyrapotyra/* $Id: GetSig.hpp 4323 2009-01-27 13:48:12Z potyra $ * * GetSig: determine the value of a signal. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GETSIG_HPP_INCLUDED #define __GETSIG_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" namespace intermediate { //! determine the value of a signal. /** This class can determine the value of a Signal. * * Read Operands: src * Write Operands: dst * Reserved Operands: att * * src: contains the pointer to a signal instance. * dst: destination of the value of the signal. * att: reserved (might be used for attributes later on). * * Operation: dst = value_of_the_signal(src) */ class GetSig : public OpCode { public: //! c'tor /** @param source source containing the pointer to the signal. * @param dest destination operand for the value of the signal. * @param attr reserved. */ GetSig( Operand *source, Operand *dest, Operand *attr ) : src(source), dst(dest), att(attr) { assert(source->type == OP_TYPE_POINTER); assert(dest->type != OP_TYPE_POINTER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! source operand Operand *src; //! destination operand Operand *dst; //! reserved Operand *att; protected: virtual ~GetSig() { util::MiscUtil::terminate(this->src); util::MiscUtil::terminate(this->dst); util::MiscUtil::terminate(this->att); } }; }; /* namespace intermediate */ #endif /* __GETSIG_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/ROffset.hpp0000664000175000017500000000411011457317512021173 0ustar potyrapotyra/* $Id: ROffset.hpp 4980 2010-10-19 13:38:18Z potyra $ * * ROffset: calculate record offset (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __R_OFFSET_HPP_INCLUDED #define __R_OFFSET_HPP_INCLUDED #include #include "intermediate/operands/Register.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/container/Type.hpp" namespace intermediate { //! Calculate the record offset to a given base pointer and a given type. /** This class will calculate the record offset for a given base * pointer and a given type. * * Read operands: base, offset, * Meta information operand: rtype * Write operands: dst * * Operation: dst = b + relative offset(rtype.offset) * * FIXME need to know about the kind (signal/variable/driver), in order * to advance to the element. */ class ROffset : public OpCode { public: ROffset( Operand *b, ImmediateOperand *off, Type *t, Register *destination ) : base(b), offset(off), rtype(t), dst(destination) { assert(b->type == OP_TYPE_POINTER); assert(off->type == OP_TYPE_INTEGER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } /** base pointer to record */ Operand *base; /** integral record element position (0=first element, 1=second..) */ ImmediateOperand *offset; /** referred type of the record */ Type *rtype; /** destination operand */ Register *dst; protected: virtual ~ROffset() { util::MiscUtil::terminate(this->base); util::MiscUtil::terminate(this->offset); util::MiscUtil::terminate(this->rtype); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __R_OFFSET_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/EndTransfer.hpp0000664000175000017500000000440511137610234022035 0ustar potyrapotyra/* $Id: EndTransfer.hpp 4323 2009-01-27 13:48:12Z potyra $ * * EndTransfer: free space for transfer region again. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __END_TRANSFER_HPP_INCLUDED #define __END_TRANSFER_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Reference.hpp" #include "intermediate/operands/ImmediateOperand.hpp" namespace intermediate { //! free space for the transfer region. /** This opcode will free space for the named transfer region. * * Read operands: src, cleanupStack * Write operands: no publicly visible operands. * * Operation: * Free space for the transfer section of component src at an * implementation defined location, in case cleanupStack is set. * * Errors: * It is an error if EndTransfer wasn't called after BeginTransfer was * called from within the same text segment. * It is an error if EndTransfer references a different component * than the preceding BeginTransfer call. */ class EndTransfer : public OpCode { public: //! c'tor /** @param source reference to a component denoting the transfer * section. * @param cleanup when executing end transfer, cleanup the * stack entries or not? (useful for _create calls, * which create processes that need the parent stack to * be present). */ EndTransfer( Reference *source, ImmediateOperand *cleanup ) : src(source), cleanupStack(cleanup) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! references a component (denoting the transfer region of it) Reference *src; //! cleanup the stack ImmediateOperand *cleanupStack; protected: virtual ~EndTransfer() { util::MiscUtil::terminate(this->src); util::MiscUtil::terminate(this->cleanupStack); } }; }; /* namespace intermediate */ #endif /* __END_TRANSFER_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Mov.hpp0000664000175000017500000000306311137610234020362 0ustar potyrapotyra/* $Id: Mov.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Mov: move (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __MOV_HPP_INCLUDED #define __MOV_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" namespace intermediate { //! move data from one virtual register to another one. /** This class represents the MOV opcode, which moves data * from one virtual register into another one. Based on operand * types, it can also move data from or to memory. * * read operands: src * write operands: dst * Operation: dst = src */ class Mov : public OpCode { public: //! c'tor /** @param source source of the operation. * @param destination destination operand. */ Mov( Operand *source, Operand *destination ) : src(source), dst(destination) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! source of the instruction Operand *src; //! destination Operand *dst; protected: virtual ~Mov() { util::MiscUtil::terminate(this->src); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __MOV_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/GetParam.hpp0000664000175000017500000000441711457032065021332 0ustar potyrapotyra/* $Id: GetParam.hpp 4958 2010-10-18 11:49:09Z potyra $ * * GetParam: Get a parameter in the transfer region. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GET_PARAM_HPP_INCLUDED #define __GET_PARAM_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Reference.hpp" namespace intermediate { //! Copy slot in the transfer region of a container to dest. /** This opcode will copy source in the transfer slot of container * container into the dst operand. * * Read Operands: cnt, src * Write operands: dst * * Operation: * copy src residing in the slot defined by cnt/src to dst. * * Errors: * GetParam must be evaluated after a corresponding BeginTransfer * statement in the same text segment before a corresponding * EndTransfer statement. * * The Reference to the container must match the Reference to * BeginTransfer. * * Hints: * Useful for OUT/INOUT variable parameters, to access the result. * Should not be annotated foreign, as this would be very hard to * map to a native C call for example. */ class GetParam : public OpCode { public: //! c'tor /** @param source source operand living in container * @param cnt Reference to the container * @param dest destination operand. */ GetParam( Reference *source, Reference *cnt, Operand *dest ) : src(source), container(cnt), dst(dest) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! source operand (item in transfer segment of container) Reference *src; //! referenced container Reference *container; //! destination operand. Operand *dst; protected: virtual ~GetParam() { util::MiscUtil::terminate(this->src); util::MiscUtil::terminate(this->container); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __GET_PARAM_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Jb.hpp0000664000175000017500000000333411137610234020155 0ustar potyrapotyra/* $Id: Jb.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Jb: jump below (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __JB_HPP_INCLUDED #define __JB_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" #include "intermediate/container/Label.hpp" namespace intermediate { //! jump below /** This class will jump to target, in case left is smaller than right. * * Read operands: left, right, trg. * * left operand one comparison operand (integer) * right operand second comparison operand (integer) * trg destination address (label only) * * Operation: if (left < right) /PC/ = trg; */ class Jb : public OpCode { public: //! c'tor /** @param l left operand to compare * @param r right operand to compare * @param target jump to target, if lleft); util::MiscUtil::terminate(this->right); util::MiscUtil::terminate(this->trg); } }; }; /* namespace intermediate */ #endif /* __JB_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Jne.hpp0000664000175000017500000000331211137610234020332 0ustar potyrapotyra/* $Id: Jne.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __JNE_HPP_INCLUDED #define __JNE_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" #include "intermediate/container/Label.hpp" #include namespace intermediate { //! jump not equal /** This class will perform a jump to given CodeContainer, if * the left operand is not equal to the right operand. * * Read Operands: left, right, trg * Changes: /PC/ * * left operand: one comparison operand (integer) * right operand: idempotent comparision operand (integer) * trg: destination address (label only). * * Operation: if (left != right) /PC/=trg */ class Jne : public OpCode { public: //! c'tor /** @param l left operand to compare * @param r right operand to compare * @param target jump to target, if l==r. */ Jne( Operand *l, Operand *r, Label *target ) : left(l), right(r), trg(target) { assert(l->type == OP_TYPE_INTEGER); assert(r->type == OP_TYPE_INTEGER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! left operand Operand *left; //! right operand Operand *right; //! destination, if left==right. Label *trg; }; }; /* namespace intermediate */ #endif /* __JNE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/IMul.hpp0000664000175000017500000000355711137610234020477 0ustar potyrapotyra/* $Id: IMul.hpp 4323 2009-01-27 13:48:12Z potyra $ * * IMul: integer multiplication (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __IMUL_HPP_INCLUDED #define __IMUL_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Register.hpp" #include namespace intermediate { //! integer multiplication /** This class will perform an integer multiplication. * The main use of it is for determining sizes/offsets of arrays. * * In case that left * right is a bigger value than dst can store, the * result is undefined. * * Read Operands: left, right * Write Operands: dst * * left operand: one multiplication operand (any type). * right operand: one multiplication operand (any type) * dst: direct operand (any type) * * Operation: dst = left * right */ class IMul : public OpCode { public: //! c'tor /** @param l left operand * @param r right operand * @param dst destination register */ IMul( Operand *l, Operand *r, Register *destination ) : left(l), right(r), dst(destination) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! left operand Operand *left; //! right operand Operand *right; //! destination Register *dst; protected: virtual ~IMul() { util::MiscUtil::terminate(this->left); util::MiscUtil::terminate(this->right); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __IMUL_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Sub.hpp0000664000175000017500000000342011137610234020347 0ustar potyrapotyra/* $Id: Sub.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Sub: substract values. (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SUB_HPP_INCLUDED #define __SUB_HPP_INCLUDED #include "intermediate/operands/Register.hpp" namespace intermediate { //! substract the right operand from the left /** This class will substract the right operand from the left operand * and store the result into the dst register. * In case that left - right is a smaller value, than dst can store, * the result is undefined. * * Read operands left, right. * Write operands: dst * * left operand: Minuend * right operand: Subtrahend * dst: destination operand, to which the result will get written (any * virtual register). */ class Sub : public OpCode { public: //! c'tor /** @param l minuend * @param r subtrahend * @param destination destination register. */ Sub( Operand *l, Operand *r, Register *destination ) : left(l), right(r), dst(destination) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! left operand Operand *left; //! right operand Operand *right; //! destination Register *dst; protected: virtual ~Sub() { util::MiscUtil::terminate(this->left); util::MiscUtil::terminate(this->right); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __SUB_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Jbe.hpp0000664000175000017500000000340411137610234020320 0ustar potyrapotyra/* $Id: Jbe.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Jbe: jump below or equal (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __JBE_HPP_INCLUDED #define __JBE_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" #include "intermediate/container/Label.hpp" namespace intermediate { //! jump below or equal /** This class will jump to target, in case left is smaller or equal than * right. * * Read operands: left, right, trg. * * left operand one comparison operand (integer) * right operand second comparison operand (integer) * trg destination address (label only) * * Operation: if (left <= right) /PC/ = trg; */ class Jbe : public OpCode { public: //! c'tor /** @param l left operand to compare * @param r right operand to compare * @param target jump to target, if lleft); util::MiscUtil::terminate(this->right); util::MiscUtil::terminate(this->trg); } }; }; /* namespace intermediate */ #endif /* __JB_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Abort.hpp0000664000175000017500000000227111173123633020672 0ustar potyrapotyra/* $Id: Abort.hpp 4479 2009-04-20 16:49:31Z potyra $ * * Abort: Abort simulation on error (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ABORT_HPP_INCLUDED #define __ABORT_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" namespace intermediate { //! Abort the simulation on error. /** This intermediate opcode can be used to wishfully determinate * the simulation with on errors. * Example usage would be runtime subtype checks that fail. * * Read operands: None * Write operands: None * * Operation: Immediately abort simulation with an error. */ class Abort : public OpCode { public: //! c'tor Abort() {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } }; }; /* namespace intermediate */ #endif /* __ABORT_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Log.hpp0000664000175000017500000000276511137610234020352 0ustar potyrapotyra/* $Id: Log.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Log: Log a character (intermediate opcode). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LOG_HPP_INCLUDED #define __LOG_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" namespace intermediate { //! log a character /** This opcode can be used to log a character during the simulation. * * Read operands: level operand, target operand. * Write operands: implicit logging channel. * * Operation: * Log a character c at a desired level lvl. * If lvl is -1, then severity level will not be prepended. */ class Log : public OpCode { public: //! c'tor /** @param level desired log level * @param character char to log */ Log( Operand *level, Operand *character ) : lvl(level), c(character) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! log level Operand *lvl; //! character to log Operand *c; protected: virtual ~Log() { util::MiscUtil::terminate(this->lvl); util::MiscUtil::terminate(this->c); } }; }; /* namespace intermediate */ #endif /* __LOG_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Jmp.hpp0000664000175000017500000000241411137610234020346 0ustar potyrapotyra/* $Id: Jmp.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Jmp: unconditional jump (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __JMP_HPP_INCLUDED #define __JMP_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/container/Label.hpp" namespace intermediate { //! unconditioned jump /** This opcode will make an unconditional jump to target. * read operands: label * Changes: /PC/ * * target operand: Label. * Operation: /PC/ = Label * */ class Jmp : public OpCode { public: //! c'tor /** @param target target of the jump. */ Jmp(Label *target) : trg(target) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! target to jump to. Label *trg; protected: virtual ~Jmp() { util::MiscUtil::terminate(this->trg); } }; }; /* namespace intermediate */ #endif /* __JMP_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Proc.hpp0000664000175000017500000000335511137610234020530 0ustar potyrapotyra/* $Id: Proc.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Proc: Generate a process with initial subroutine. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PROC_HPP_INCLUDED #define __PROC_HPP_INCLUDED namespace intermediate { #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Reference.hpp" //! create a process with given subprogram. /** Proc can be used to create a process. Basically it defines a Call which gets * delayed and executed as own process. * Proc must be embedded with begintrans/setparam/endtrans opcodes. * The following endtrans opcode must not erase the stack (as this would * otherwise corrupt the process's stack). * * Read Operands: target (pointer referencing the target code container) * Write Operands: None in current process context. * * Operation: * Register target as a ready process in the scheduler, giving * the current transfer stack frame (as created by begintrans) * as parameter. */ class Proc : public OpCode { public: //! c'tor /** @param target subprogram that defines the process */ Proc(Reference *destination) : dst(destination) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! target (name) of the subprogram that should defines the process. Reference *dst; }; }; /* namespace intermediate */ #endif /* __PROC_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/GetSimTime.hpp0000664000175000017500000000263611173123633021637 0ustar potyrapotyra/* $Id: GetSimTime.hpp 4479 2009-04-20 16:49:31Z potyra $ * * GetSimTime: retrieve the current simulation time. * * Copyright (C) 2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GETSIMTIME_HPP_INCLUDED #define __GETSIMTIME_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" namespace intermediate { //! Retrieve the current simulation time. /** This intermediate opcode can be used to retrieve the current simulation * time. * * Read operands: No explicit operands read. * Write operands: dst. * * Operation: store the current simulation time in dst. */ class GetSimTime : public OpCode { public: //! c'tor /** @param destination destination operand. */ GetSimTime(Operand *destination) : dst(destination) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } /** destination operand */ Operand *dst; protected: virtual ~GetSimTime() { util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __GETSIMTIME_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/OpCode.hpp0000664000175000017500000000211311137610234020765 0ustar potyrapotyra/* $Id: OpCode.hpp 4323 2009-01-27 13:48:12Z potyra $ * * OpCode: base class for all opcodes (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __OP_CODE_HPP_INCLUDED #define __OP_CODE_HPP_INCLUDED #include "intermediate/Node.hpp" namespace intermediate { //! base class for all opcodes. /** OpCode is a generic base class for all opcodes of the intermediate code. * * All opcodes descriptions should be annotated with what they do. * read operands: all operands that will get read from. * write operands: all operands, that will get written to. * Operation: effect of the opcode. * * Others: /PC/ is the implicit program counter. * * EVERY opcode will implicitely perform a /PC/ = /PC/ + 1 */ class OpCode : public Node { public: }; }; /* namespace intermediate */ #endif /* __OP_CODE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/AOffset.hpp0000664000175000017500000000410611137610234021147 0ustar potyrapotyra/* $Id: AOffset.hpp 4323 2009-01-27 13:48:12Z potyra $ * * AOffset: Calculate array offsets (intermediate opcode). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __A_OFFSET_HPP_INCLUDED #define __A_OFFSET_HPP_INCLUDED #include #include "intermediate/operands/Register.hpp" #include "intermediate/container/Type.hpp" namespace intermediate { //! Calculate the array offset to a given base pointer and a given type. /** This class will calculate the array offset for a given base * pointer and a given type. * * Read operands: base, offset, * Meta information operand: rtype * Write operands: dst * * Operation: dst = b + array offset(rtype[offset]) */ class AOffset : public OpCode { public: //! c'tor /** @param b base address of the array. * @param off index offset (0=first elem, 1=second...) * @param t corresponding type declaration. * @param destination destination operand */ AOffset( Operand *b, Operand *off, Type *t, Register *destination ) : base(b), offset(off), atype(t), dst(destination) { assert(b->type == OP_TYPE_POINTER); assert(off->type == OP_TYPE_INTEGER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } /** base pointer to array */ Operand *base; /** integral array position (0=first element, 1=second..) */ Operand *offset; /** referred array type */ Type *atype; /** destination operand */ Register *dst; protected: virtual ~AOffset() { util::MiscUtil::terminate(this->base); util::MiscUtil::terminate(this->offset); util::MiscUtil::terminate(this->atype); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __A_OFFSET_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Return.hpp0000664000175000017500000000222211137610234021074 0ustar potyrapotyra/* $Id: Return.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Return: return from subroutine (intermediate opcode). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RETURN_HPP_INCLUDED #define __RETURN_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" namespace intermediate { //! return from a subroutine. /** This class will return from a given subroutine. * * Read operands: None. * Write operands: implicit stack pointer, implicit instruction pointer. * * No operands can be specified for Return. * * Operation: * pop instruction pointer from stack. */ class Return : public OpCode { public: //! c'tor Return() {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } }; }; #endif /* __RETURN_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Suspend.hpp0000664000175000017500000000241311137610234021240 0ustar potyrapotyra/* $Id: Suspend.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Suspend: suspend the current process (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SUSPEND_HPP_INCLUDED #define __SUSPEND_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" namespace intermediate { //! suspend the current process /** This class will signal the kernel/scheduler to suspend the current * process. * * Read Operands: None * Write Operands: None * * Operation: Suspend the current process until a wakeup condition * occurs. If no condition was registered to the scheduler * beforehand, the process will suspend indefinitely. */ class Suspend : public OpCode { public: //! c'tor Suspend() {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } }; } /* namespace intermediate */ #endif /* __SUSPEND_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Update.hpp0000664000175000017500000000343111460057355021052 0ustar potyrapotyra/* $Id: Update.hpp 4996 2010-10-21 15:40:29Z potyra $ * * Update: update a signal (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __UPDATE_HPP_INCLUDED #define __UPDATE_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include #include "intermediate/operands/Operand.hpp" namespace intermediate { //! update a given driver /** This class will update a given driver after a given delay, assuming the * initial transport mechanism. * * Read operands src, delay * Write operands: dst * * src: source value of the operation (any type allowed) * delay: delay value (integer) * dst: DirectOperand pointing to the driver (pointer) * * Operation: call to the kernel, to add to given driver. */ class Update : public OpCode { public: Update( Operand *source, Operand *delayOp, Operand *dest ) : src(source), delay(delayOp), dst(dest) { assert(delay->type == OP_TYPE_INTEGER); assert(dst->type == OP_TYPE_POINTER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! source operand Operand *src; //! delay operand Operand *delay; //! destination operand Operand *dst; protected: virtual ~Update() { util::MiscUtil::terminate(this->src); util::MiscUtil::terminate(this->delay); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __UPDATE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Call.hpp0000664000175000017500000000324611137610234020477 0ustar potyrapotyra/* $Id: Call.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Call: Call a subroutine (intermediate opcode). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CALL_HPP_INCLUDED #define __CALL_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Reference.hpp" namespace intermediate { //! call given subprogram /** This class will call a given subprogram. * The destination of a call must be the name of a code container. This code * container must be in the same nesting level as the current code container, * or above the current code container. * * Read operands: target (pointer referencing the target code container) * Write operands: implicit stack pointer, stack, * implicit instruction pointer * * Operation: * push instruction pointer * push target stack segment to stack * instruction pointer = target */ class Call : public OpCode { public: //! c'tor /** @param target called subprogram */ Call(Reference *destination) : dst(destination) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! target (name) of the subprogram. Reference *dst; protected: virtual ~Call() { util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __CALL_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Div.hpp0000664000175000017500000000304511137610234020343 0ustar potyrapotyra/* $Id: Div.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Div: division (intermediate opcode). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DIV_HPP_INCLUDED #define __DIV_HPP_INCLUDED namespace intermediate { //! division /** This class will perform a division. * * Errors: right is 0. * * Read Operands: left, right * Write Operands: dst * * left operand: dividend (any type). * right operand: divisor (any type) * dst: resulting quotient (any type) * * Operation: dst = left / right */ class Div : public OpCode { public: //! c'tor /** @param l left operand * @param r right operand * @param dst destination register */ Div( Operand *l, Operand *r, Register *destination ) : left(l), right(r), dst(destination) {} //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! left operand Operand *left; //! right operand Operand *right; //! destination Register *dst; protected: virtual ~Div() { util::MiscUtil::terminate(this->left); util::MiscUtil::terminate(this->right); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __DIV_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Je.hpp0000664000175000017500000000327211137610234020161 0ustar potyrapotyra/* $Id: Je.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __JE_HPP_INCLUDED #define __JE_HPP_INCLUDED #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/Operand.hpp" #include "intermediate/container/Label.hpp" #include namespace intermediate { //! jump equal /** This class will perform a jump to given CodeContainer, if * the left operand is equal to the right operand. * * Read Operands: left, right, trg * Changes: /PC/ * * left operand: one comparison operand (any type allowed) (FIXME integer * only?) * right operand: idempotent comparision operand (any type allowed) * trg: destination address (label only). * * Operation: if (left == right) /PC/=trg */ class Je : public OpCode { public: //! c'tor /** @param l left operand to compare * @param r right operand to compare * @param target jump to target, if l==r. */ Je( Operand *l, Operand *r, Label *target ) : left(l), right(r), trg(target) { assert(l->type == r->type); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! left operand Operand *left; //! right operand Operand *right; //! destination, if left==right. Label *trg; }; }; /* namespace intermediate */ #endif /* __JE_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/WakeAt.hpp0000664000175000017500000000347411137610234021003 0ustar potyrapotyra/* $Id: WakeAt.hpp 4323 2009-01-27 13:48:12Z potyra $ * * WakeAt: Tell the scheduler to wake the current process at a given * simulation time. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __WAKE_AT_HPP_INCLUDED #define __WAKE_AT_HPP_INCLUDED #include namespace intermediate { //! register that the current process should be resumed at a given time. /** This class will tell the scheduler, to resume the current process * at a given time. The scheduler may however also resume the current * process earlier, in case a signal registered via WakeOn had an * event. * In case the process resumes due to an event, the timeout is also * cleared, and must eventually get reset. * Issueing more than one WakeAt before a call to Suspend the current * process leads to undefined behaviour. * * read operands: wakeTime * write operands: no explicit write operands * * Operation: sched->setTimeOut(wakeTime); */ class WakeAt : public OpCode { public: //! c'tor /** @param t simulation time value, at which the process should * resume. */ WakeAt(Operand *t) : wakeTime(t) { assert(t->type == OP_TYPE_INTEGER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! scheduled resume time. Operand *wakeTime; protected: virtual ~WakeAt() { util::MiscUtil::terminate(this->wakeTime); } }; }; /* namespace intermediate */ #endif /* __WAKE_AT_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/Add.hpp0000664000175000017500000000372111137610234020312 0ustar potyrapotyra/* $Id: Add.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Add: addition (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ADD_HPP_INCLUDED #define __ADD_HPP_INCLUDED #include "intermediate/operands/Register.hpp" namespace intermediate { //! add two operands and return a new operand as result. /** This class will add both operands together and put the result in the * target register. * In case that left + right is a bigger value than dst can store, the * result is undefined. * * Read operands: left, right * Write operands: dst * * left operand: left operand for addition * right operand: right operand for addition * dst: destination operand, to which the result will get written to (any * virtual register*) * * Operation : dst = left + right * * all operands must have the same type. * */ class Add : public OpCode { public: //! c'tor /** @param l left source operand * @param r right source operand * @param destination destination register. */ Add( Operand *l, Operand *r, Register *destination ) : left(l), right(r), dst(destination) { assert(l->type == r->type); assert(l->type == destination->type); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! left operand Operand *left; //! right operand Operand *right; //! destination Register *dst; protected: virtual ~Add() { util::MiscUtil::terminate(this->left); util::MiscUtil::terminate(this->right); util::MiscUtil::terminate(this->dst); } }; }; /* namespace intermediate */ #endif /* __ADD_HPP_INCLUDED */ fauhdlc-20130704/intermediate/opcodes/WakeOn.hpp0000664000175000017500000000333411137610234021006 0ustar potyrapotyra/* $Id: WakeOn.hpp 4323 2009-01-27 13:48:12Z potyra $ * * WakeOn: Tell the scheduler to wake the current process on a signal event. * (intermediate opcode) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __WAKE_ON_HPP_INCLUDED #define __WAKE_ON_HPP_INCLUDED #include namespace intermediate { //! register a signal to the scheduler on which to wake the current process. /** This class represents the wake_on opcode. * The currently running process should be made runnable again, if the signal * registered via WakeOn showed activity. * Issueing more than one WakeOn statement will add to the schedulers * internal sensitivity set. The set will only be cleared after the * process was resumed from a suspend statement. * * read operands: src * write operands: None, implicit sensitivity set of scheduler. * Operation: sched->addSensitivity(src); */ class WakeOn : public OpCode { public: //! c'tor /** @param source pointer to a signal. */ WakeOn( Operand *source ) : src(source) { assert(source->type == OP_TYPE_POINTER); } //! Accept a Visitor. /** All intermediate code nodes need to implement this method. * * @param v the Visitor that can visit this node. */ virtual void accept(Visitor& v) { v.visit(*this); } //! source of the instruction Operand *src; protected: virtual ~WakeOn() { util::MiscUtil::terminate(this->src); } }; }; /* namespace intermediate */ #endif /* __WAKE_ON_HPP_INCLUDED */ fauhdlc-20130704/util/0000775000175000017500000000000012165333100013751 5ustar potyrapotyrafauhdlc-20130704/util/mangle_names.h0000664000175000017500000000241611137606566016574 0ustar potyrapotyra/* $Id: mangle_names.h 4322 2009-01-27 13:34:46Z potyra $ * * Mangle/Demangle VHDL names to intermediate code names. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __MANGLE_NAMES_H_INCLUDED #define __MANGLE_NAMES_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #include /** mangle the VHDL name to an intermediate code name and store it in the * buffer of size sz at dst. * @param name name to mangle * @param dst pointer to buffer * @param sz size of buffer. * @return number of bytes written to dst. */ extern int mangle_name(const char *name, char *dst, size_t sz); /** demangle the intermediate code name and store it in the buffer * of size sz pointed to by dst. * @param name intermediate code name * @param dst buffer into which the demangeld vhdl name will get stored * @param sz size of dst. * @return number of bytes written to dst. */ extern int demangle_name(const char *name, char *dst, size_t sz); #ifdef __cplusplus }; /* extern "C" */ #endif #endif /* __MANGLE_NAMES_H_INCLUDED */ fauhdlc-20130704/util/MiscUtil.hpp0000664000175000017500000001317311137606566016241 0ustar potyrapotyra/* $Id: MiscUtil.hpp 4322 2009-01-27 13:34:46Z potyra $ * * Misc. utility functions. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __MISC_UTIL_HPP_INCLUDED #define __MISC_UTIL_HPP_INCLUDED #include #include #include namespace util { /** This class aggregates misc. static utility functions. */ class MiscUtil { public: /** functor, to compare to pointers by their * == operator. * @param obj1 first object to compare. * @param obj2 second object to compare. * @return true if both object pointers are nonnull and the * == operator returns true. */ template static bool compareObject(const T* obj1, const T* obj2); /** compare two lists of pointers. * @param l1 first list of pointers. * @param l2 second list of pointers. * @return true only if the lists have the same length and * the == operator of each object at the same * position in the list returns true. */ template static bool listMatch(const std::list& l1, const std::list& l2); /** compare two lists of pointers. * @param l1 first list of pointers. * @param l2 second list of pointers. * @param compare comparison functor. * @return true only if the lists have the same length and * the given compare functor of each object at the same * position in the list returns true. */ template static bool listMatch(const std::list& l1, const std::list& l2, bool (*compare)(const T*, const T*)); //! convert val to a string using << operator overloads. /** Template restriction: An overloaded << operator for T * must exist. * @param val value that should get converted to a string. * @result val converted to a string. */ template static std::string toString(const T &val); //! check if needle is in haystack dereferencing pointers. /** check if the element needle is contained in iteratable haystack * dereferncing pointers for comparison. * @param needle element to look for * @param haystack list which gets iterated over * @return true if needle is in haystack */ template static bool listContainsObj(const T& haystack, const U needle); //! check if reference starts with begin (dereferncing ptrs.) /** check if the list reference starts with the list beginning * dereferencing pointers for comparison. * @param begin possible beginning of reference. * @param list that may contain begin. * @return true, if reference starts with begin. */ template static bool listStartsWith(const std::list begin, const std::list reference); //! apply delete on every element of a list and clear the list. /** delete any element of a list, and clear the list. * @param l list that should get its elements deleted. */ template static void ldelete(T& l); //! apply decRef on every element of a list. /** apply decRef on every element of a list and delete the list * afterwards. * @param l pointer to list in question. */ template static void lterminate(T*& l); //! check if item is non-null and call decRef() if so. /** check if item is non-null and call decRef() if so. * @param item AstNode that should get terminated. */ template static void terminate(T& item); //! remove and delete contents of a list if functor yields true. /** remove and delete contents of given list l in case the * functor returns true for an element of the list. * @param l work list, that should get filtered. * @param functor predicate (instance/function), that can be called * with a T* element as argument and returns true or false. */ template static void ldelete_if(T& l, U functor); //! functor: return the second element of a pair /** @param t pair * @return second element */ template static typename T::second_type select2nd(T& t) { return t.second; } //! functor: return the first element of a pair /** @param t pair * @return first element */ template static typename T::first_type select1st(T& t) { return t.first; } //! Predicate class: set operation not in /** This class can be used when the predicate "not in" is needed. * T: any forward iteratible sequence (that goes through std::fine). */ template class NotIn { public: //! C'tor /** @param refContainer reference sequence container. */ NotIn(T &refContainer) : ref(refContainer) {}; //! predicate operator /** @param i object that will be checked if it is contained in * the reference sequence. * @return true, if i is not in reference, false otherwise. */ template bool operator()(U i) { if (std::find(ref.begin(), ref.end(), i) == ref.end()) { return true; } return false; } private: //! reference container T &ref; }; /** Take a list of pointers and output each one to stream via <<. * @param l pointer to list, may be NULL. * @param stream stream to put elements to. * @param delim use this char as a delimiter between two * elements. */ template static void listPut(T *l, std::ostream &stream, const char *delim); }; }; /* namespace util */ #include "util/MiscUtil.tpp" #endif /* __MISC_UTIL_HPP_INCLUDED */ fauhdlc-20130704/util/mangle_names.c0000664000175000017500000000330711137606566016567 0ustar potyrapotyra/* $Id: mangle_names.c 4322 2009-01-27 13:34:46Z potyra $ * * Mangle/Demangle VHDL names to intermediate code names. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "util/mangle_names.h" #include #include #include #include static void replace_all(char *b, size_t sz, const char *tok, const char *rep) { size_t tok_len; size_t rep_len; size_t cnt; size_t avail; char *remainder; char *s; char *dest; tok_len = strlen(tok); rep_len = strlen(rep); for (;;) { s = strstr(b, tok); if (s == NULL) { break; } remainder = s + tok_len; dest = s + rep_len; if (dest != remainder) { cnt = strlen(remainder) + 1; avail = sz - (dest - b); if (cnt < avail) { cnt = avail; } memmove(dest, remainder, cnt); } memcpy(s, rep, rep_len); } b[sz - 1] = '\0'; } int mangle_name(const char *name, char *dst, size_t sz) { int r; r = snprintf(dst, sz, "%s", name); assert(r >= 0); assert((size_t)r < sz); replace_all(dst, sz, ":", "__c_"); replace_all(dst, sz, "[", "__b_"); replace_all(dst, sz, "]", "__B_"); replace_all(dst, sz, " ", "__e_"); replace_all(dst, sz, ",", "__s_"); return strlen(dst); } int demangle_name(const char *name, char *dst, size_t sz) { snprintf(dst, sz, "%s", name); replace_all(dst, sz, "__c_", ":"); replace_all(dst, sz, "__b_", "["); replace_all(dst, sz, "__B_", "]"); replace_all(dst, sz, "__e_", " "); replace_all(dst, sz, "__s_", ","); return 0; } fauhdlc-20130704/util/MiscUtil.tpp0000664000175000017500000000545511137606566016261 0ustar potyrapotyra/* $Id: MiscUtil.tpp 4322 2009-01-27 13:34:46Z potyra $ * vim:tabstop=8:shiftwidth=8:filetype=cpp:textwidth=72: * * Misc. utility functions, template implementations. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include namespace util { template bool MiscUtil::compareObject(const T* obj1, const T* obj2) { if ((obj1 == NULL) || (obj2 == NULL)) { return false; } return (*obj1) == (*obj2); } template bool MiscUtil::listMatch(const std::list& l1, const std::list& l2) { if (l1.size() != l2.size()) { return false; } return std::equal(l1.begin(), l1.end(), l2.begin(), MiscUtil::compareObject); } template bool MiscUtil::listMatch( const std::list& l1, const std::list& l2, bool (*compare)(const T*, const T*)) { if (l1.size() != l2.size()) { return false; } return std::equal(l1.begin(), l1.end(), l2.begin(), compare); } template std::string MiscUtil::toString(const T &val) { std::stringstream stream; stream << val; std::string result = stream.str(); return result; } template bool MiscUtil::listContainsObj(const T& haystack, const U needle) { for (typename T::const_iterator i = haystack.begin(); i != haystack.end(); i++) { if (MiscUtil::compareObject((*i), needle)) { return true; } } return false; } template bool MiscUtil::listStartsWith(const std::list begin, const std::list reference) { if (begin.size() > reference.size()) { return false; } return std::equal(begin.begin(), begin.end(), reference.begin(), MiscUtil::compareObject); } template void MiscUtil::ldelete(T& l) { for (typename T::const_iterator i = l.begin(); i != l.end(); i++) { delete *i; } l.clear(); } template void MiscUtil::lterminate(T*& l) { if (l == NULL) { return; } delete l; l = NULL; } template void MiscUtil::terminate(T& item) { item = NULL; } template void MiscUtil::ldelete_if(T& l, U functor) { for (typename T::iterator i = l.begin(); i != l.end();) { if (functor(*i)) { typename T::value_type cur = *i; i = l.erase(i); delete cur; continue; } i++; } } template void MiscUtil::listPut(T *l, std::ostream &stream, const char *delim) { if (l == NULL) { stream << "(null)"; return; } for (typename T::const_iterator i = l->begin(); i != l->end(); /* nothing */) { stream << **i; i++; if (i != l->end()) { stream << delim; } } } }; /* namespace util */ fauhdlc-20130704/util/GarbageCollect.hpp0000664000175000017500000000202711142016256017325 0ustar potyrapotyra/* $Id: GarbageCollect.hpp 4345 2009-02-03 10:30:06Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GARBAGE_COLLECT_HPP_INCLUDED #define __GARBAGE_COLLECT_HPP_INCLUDED #if HAVE_GC_GC_CPP_H #include #endif /* HAVE_GC_GC_CPP_H */ namespace util { #if HAVE_GC_GC_CPP_H class GarbageCollect : public gc::gc { public: //! initialize garbage collection. static void initialize(void) { GC_INIT(); } protected: /** virtual d'tor */ virtual ~GarbageCollect() {} }; #else /* ! HAVE_GC_GC_CPP_H */ class GarbageCollect { public: //! dummy initialization, do nothing. static void initialize(void) {} protected: //! virtual d'tor virtual ~GarbageCollect() {} }; #endif /* HAVE_GC_GC_CPP_H */ }; /* namespace util */ #endif /* __GARBAGE_COLLECT_HPP_INCLUDED */ fauhdlc-20130704/util/basetypes.h0000664000175000017500000000132111137606566016137 0ustar potyrapotyra/* $Id: basetypes.h 4322 2009-01-27 13:34:46Z potyra $ * * Common base type declarations. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __BASE_TYPES_H_INCLUDED #define __BASE_TYPES_H_INCLUDED #include /** representation of universal integer inside the compiler/interpreter. */ typedef int64_t universal_integer; /** representation of universal real inside the compiler/interpreter */ typedef double universal_real; #endif /* __BASE_TYPES_H_INCLUDED */ fauhdlc-20130704/tests/0000775000175000017500000000000012165333077014153 5ustar potyrapotyrafauhdlc-20130704/tests/run-tests.py0000775000175000017500000003315511717540643016504 0ustar potyrapotyra#!/usr/bin/python # $Id: run-tests.py 5104 2012-02-17 21:07:47Z potyra $ # Run the test suite. # # Copyright (C) 2008-2009 FAUmachine Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. import os import subprocess import time import re import sys # some colors COL_RED="\033[31m\033[1m" COL_GREEN="\033[32m\033[1m" COL_YELLOW="\033[33m\033[1m" COL_NORM="\033[0m" class file_handling: @classmethod def setup_filehandling(cls, srcdir, builddir): cls._srcdir = srcdir cls._builddir = builddir @classmethod def get_src_name(cls, filename, prefix="."): return "%s/%s/%s" % (cls._srcdir, prefix, filename) @classmethod def get_output_name(cls, filename, prefix="."): dir = "%s/%s" % (cls._builddir, prefix) if not os.path.isdir(dir): print "Creating directory %s" % dir os.mkdir(dir) return "%s/%s" % (dir, filename) @classmethod def get_compiler(cls): return "../fauhdlc" @classmethod def get_intepreter(cls): return "../interpreter/fauhdli" class eval_helper: """ helper for string parsing """ @classmethod def eval_opt_list(cls, s): """ evaluate an option list and return a dictionary eval_opt_list will take a string, and find all NAME="option" entries. The entries are stored in a dictionary with NAME as the key and the option (without quotes) as the value. This dictionary is returned. """ if not hasattr(cls, "preg"): reg = "(?P[A-Za-z0-9_]*)=\"(?P[^\"]*)\"" cls.preg = re.compile(reg) ret = {} i = cls.preg.finditer(s) for match in i: ret[match.group("name")] = match.group("entry") return ret class InterpreteTC: """ class to interprete an intermediate code file """ def __init__(self, icpath, entity="work:test_bench", debug=False): self._icpath = icpath self._entity = entity self._debug = debug self._runtime = -1 # -1: not run, 0: success, 1: failure self._status = -1 self._exit_status = -1 def _get_file_name(self, suffix): return "%s.%s" % (self._icpath, suffix) @classmethod def canUseValgrind(cls): if hasattr(cls, "useValgrind"): return cls.useValgrind # detect valgrind p = os.getenv("PATH") pathes = [x + "/valgrind" for x in p.split(":")] vgs = [os.path.isfile(x) for x in pathes] cls.useValgrind = (True in vgs) return cls.useValgrind def execute(self): fout = file(self._get_file_name("std.out"), "w") ferr = file(self._get_file_name("err.out"), "w") if InterpreteTC.canUseValgrind(): # Use the next lines for deep memory debugging. #cmd = ["valgrind", "--leak-check=full", # "--show-reachable=yes"] cmd = ["valgrind"] else: cmd = [] cmd.append(file_handling.get_intepreter()) cmd.append("-s") cmd.append(self._entity) if self._debug: cmd.append("-d") cmd.append(self._icpath) sys.stdout.write(".") sys.stdout.flush() t1 = time.time() p = subprocess.Popen(cmd, shell=False, stdout=fout, \ stderr=ferr) self._exit_status = p.wait() t2 = time.time() self._runtime = t2 - t1 fout.close() ferr.close() def _handle_err_out(self): ferr = file(self._get_file_name("err.out"), "r") fout = file(self._get_file_name("std.out"), "r") lines = ferr.readlines() ferr.close() if InterpreteTC.canUseValgrind(): # write valgrind info to separate file vout = file(self._get_file_name("valgrind.err.out"), "w") vout.writelines(lines) vout.close() sim_fin_seen = False have_critical_errs = False have_mem_errors = False critical_errs = "" for l in lines: if "Conditional jump or move depends on" in l: have_mem_errors = True lines = fout.readlines() fout.close() for l in lines: if ": simulation finished" in l: sim_fin_seen = True if "FAILURE" in l: have_critical_errs = True critical_errs += l if self._exit_status != 0: # interpreter failed self._report = "%s interpreter exited with %d%s\n" % \ (COL_RED, self._exit_status, COL_NORM) self._report += "".join(lines[-7:]) self._status = 1 return if have_critical_errs: # interpreter succeeded, but critical errors present self._report = "%sinterpreter critical errors:%s\n" % \ (COL_RED, COL_NORM) self._report += critical_errs self._status = 1 return if (not sim_fin_seen): # simulation finished not seen self._report = "%sinterpreter did not finish%s\n" % \ (COL_RED, COL_NORM) # add last 7 lines of stderr self._report += "".join(lines[-7:]) self._status = 1 return if have_mem_errors: # valgrind detected memory errors self._report = "%sinterpreter has memory errors%s\n" \ % (COL_RED, COL_NORM) self._status = 1 return # all good self._report = "%ssucceeded%s" % (COL_GREEN, COL_NORM) self._status = 0 def get_status(self): assert self._exit_status != -1 if self._status == -1: self._handle_err_out() assert self._status != -1 return self._status def __str__(self): assert self._exit_status != -1 assert self._status != -1 return self._report # symbol table class TestCase: """ class representing one test case """ def __init__(self, entry, subdir): self._name = "" self._compiler_opts = ["--freestanding"] self._exit_status = -1 # status of result. # -1: no result yet, # 0: expected result occurred (test succeeded) # 1: expected result did not occur (test failed) # 2: expected result but not expected output (warning) self._status = -1 self._subdir = subdir self._err_out = [] # (line, msg) tuples of errors that are expected but not # present in actual_errors self._missing_errors = [] # expected exit status self._expected_result = 0 self._parse(entry) self._interprete = False def _parse(self, entry): arr = entry.split(" ", 1) self._name = arr.pop(0).strip() if len(arr) == 0: return d = eval_helper.eval_opt_list(arr[0]) opts = [] if d.has_key("OPTS"): opts += d["OPTS"].split(" ") for o in opts: # VHDL file name? prefix with subdir if o[-5:].lower() == ".vhdl": src = file_handling.get_src_name(\ o, self._subdir) self._compiler_opts.append(src) else: self._compiler_opts.append(o) def _get_src_file_name(self, suffix): fn = "%s.%s" % (self._name, suffix) return file_handling.get_src_name(fn, self._subdir) def _get_out_file_name(self, suffix): fn = "%s.%s" % (self._name, suffix) return file_handling.get_output_name(fn, self._subdir) def execute(self, compiler, common_opts, output_ic=False): """ execute the test """ fout = file(self._get_out_file_name("std.out"), "w") ferr = file(self._get_out_file_name("err.out"), "w") cmd = [compiler] if len(common_opts) > 0: cmd.append(common_opts) cmd = cmd + self._compiler_opts cmd.append(self._get_src_file_name("vhdl")) if output_ic: cmd += ["-o", self._get_out_file_name("ic")] t1 = time.time() p = subprocess.Popen(cmd, shell=False, stdout=fout, \ stderr=ferr) self._exit_status = p.wait() t2 = time.time() self._runtime = t2 - t1 fout.close() ferr.close() def _store_err_out(self): f = file(self._get_out_file_name("err.out"), "r") self._err_out = f.readlines() f.close() @staticmethod def _flatten_err(line): txt = line[7:] fn = "" line = "" msg = "" try: (fn, line_t, msg) = txt.split(":", 2) line = int(line_t) msg = msg.strip() except: return None return (line, msg) def _check_errors(self): expected = self._check_vhdl() if len(expected) == 0: return # errors are expected: want 3 as exit status self._expected_result = 3 self._missing_errors = [] actual_errs = [self._flatten_err(e) for e in self._err_out \ if e[:6] == "ERROR>"] actual_errs = [e for e in actual_errs if e is not None] for line, msg in expected: corr = [ a for a in actual_errs \ if (a[0] == line) \ and msg.lower() in a[1].lower()] if len(corr) == 0: self._missing_errors.append((line, msg)) def _check_vhdl(self): lno = 0 f = file(self._get_src_file_name("vhdl"), "r") errs = [] for l in f.readlines(): lno = lno + 1 if "@ERROR@" in l: parts = l.split("@ERROR@") desc = parts[1].strip() errs.append((lno, desc)) if "test_bench" in l.lower(): self._interprete = True f.close() return errs def _get_err_out(self, num_lines=10): assertions = [l for l in self._err_out if "Assertion" in l] # assertion failure present? return it. if len(assertions) != 0: return "\n" + assertions[-1] # return last 10 lines of stderr s = "\nLast %d lines of stderr:\n\n" % num_lines s += "".join(self._err_out[-num_lines:]) s += "\n" return s def _get_error_report(self): s = "\nExpected errors missing from fauhdlc:\n" mes = [ "Line %d: %s" % (e[0], e[1]) for e in self._missing_errors ] s += "\n".join(mes) s += self._get_err_out(7) return s def _eval_interprete(self): assert self._interprete tc = InterpreteTC(self._get_out_file_name("ic")) tc.execute() self._status = tc.get_status() return str(tc) def _get_result(self): # TODO has side effects right now self._store_err_out() self._check_errors() if self._expected_result == 0: # no errors expected if self._exit_status == 0: self._status = 0 if self._interprete: return self._eval_interprete() return "%ssucceeded%s" % (COL_GREEN, COL_NORM) self._status = 1 return "%sfailed%s%s" % \ (COL_RED, COL_NORM, self._get_err_out()) # errors expected if self._expected_result == self._exit_status: if len(self._missing_errors) == 0: self._status = 0 return "%sfailed as expected%s" % \ (COL_GREEN, COL_NORM) else: self._status = 2 return "%sfailed but errors don't match%s%s"\ % (COL_YELLOW, COL_NORM, \ self._get_error_report()) self._status = 1 return "%sunexpected result%s (exit code: %d)%s" \ %(COL_RED, COL_NORM, self._exit_status, \ self._get_err_out()) def __str__(self): """ provide output by converting to string. """ if self._exit_status == -1: return "%s %swas not yet executed%s." % \ (self._name, COL_YELLOW, COL_NORM) s = "%s: " % self._name if len(self._name) < 20: s += " " * (20 - len(self._name)) s += self._get_result() return s def get_status(self): return self._status class QuietTestCase(TestCase): """ same as test-case, but don't output anything but the status """ def __init__(self, entry, subdir): # manually call parent c'tor TestCase.__init__(self, entry, subdir) def _get_err_out(self, num_lines=10): return "" def _get_error_report(self): return "" def _get_result(self): return TestCase._get_result(self) + \ " (verbose output disabled) " class TestSuite: """ parses a tests.list file, evaluating all test-cases in there """ def __init__(self, listdir): self._listfile = \ file_handling.get_src_name("tests.list", listdir) self._testcases = [] self._subdir = listdir def parse(self): f = None f = file(self._listfile, "r") lines = f.readlines() f.close() # filter out comments lines = [ l for l in lines if l[0] != '#' ] desc_line = lines.pop(0) self._parse_desc(desc_line) for l in lines: self._parse_test_case(l) def _parse_desc(self, d): opts = eval_helper.eval_opt_list(d) self._description = "Description unset!" self._common_opts = "" self._output_ic = False if opts.has_key("DESC"): self._description = opts["DESC"] if opts.has_key("COMMON_OPTS"): self._common_opts = opts["COMMON_OPTS"] if opts.has_key("OUTPUT"): if opts["OUTPUT"] == 'True': self._output_ic = True def _parse_test_case(self, s): d = eval_helper.eval_opt_list(s) tc = None if d.has_key("QUIET") and (d["QUIET"] == "True"): tc = QuietTestCase(s, self._subdir) else: tc = TestCase(s, self._subdir) self._testcases.append(tc) def execute(self): """ execute all test cases """ t1 = time.time() for tc in self._testcases: tc.execute(\ file_handling.get_compiler(), \ self._common_opts, \ self._output_ic) t2 = time.time() self._runtime = t2 - t1 def get_status(self): """ get_status -> (#succ, #failed, #warn) """ succ, failed, warn = 0, 0, 0 for tc in self._testcases: res = tc.get_status() if res == 0: succ += 1 elif res == 1: failed += 1 elif res == 2: warn += 1 else: assert False return (succ, failed, warn) def __str__(self): s = "Executing tests for %s\n" % self._description s += " common options: %s\n" % self._common_opts s += "--------------------------------------------\n" for tc in self._testcases: s += "%s\n" % tc s += "--------------------------------------------\n" s += "Summary:\n" s += " Execution took %0.02f seconds.\n" % self._runtime s += "============================================\n" return s class AllTest: def __init__(self, testfiles): self._suites = [] for td in testfiles: ts = TestSuite(td) ts.parse() self._suites.append(ts) def execute(self): t1 = time.time() for ts in self._suites: ts.execute() t2 = time.time() self._runtime = t2 - t1 def __str__(self): s = "" succ, failed, warn = 0, 0, 0 for ts in self._suites: s += "%s\n" % ts st, ft, wt = ts.get_status() succ += st failed += ft warn += wt s += "TOTAL SUMMARY:\n" s += "%d successfuls tests, %d failures, %d warnings\n" %\ (succ, failed, warn) s += "Compile time for all tests: %0.02f\n" % self._runtime return s if __name__ == "__main__": srcdir = os.getenv("srcdir", ".") file_handling.setup_filehandling(srcdir, ".") suites = ("symboltable", \ "types", \ "icode", \ "error_tests") alltest = AllTest(suites) alltest.execute() print "\n" + str(alltest) fauhdlc-20130704/tests/icode/0000775000175000017500000000000012165333076015235 5ustar potyrapotyrafauhdlc-20130704/tests/icode/proc2.vhdl0000664000175000017500000000170411137616416017143 0ustar potyrapotyra-- $Id: proc2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is procedure foo(signal a : in boolean; variable b : out boolean); end package t; package body t is procedure foo(signal a : in boolean; variable b : out boolean) is begin b := a; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is signal int_a : boolean; variable int_b : boolean; begin p : process begin int_a <= true; int_b := false; wait on int_a; foo(int_a, int_b); assert int_b report "b must be true" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/array_ports3.vhdl0000664000175000017500000000344611305712545020550 0ustar potyrapotyra-- $Id: array_ports3.vhdl 4853 2009-12-03 10:39:33Z potyra $ -- check ports which are arrays of signals. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type ba is array(integer range <>) of boolean; end package; use t.ba; ENTITY bottom IS PORT ( x : in ba(1 to 10); y : out ba ); END ENTITY bottom; ARCHITECTURE bottom_impl OF bottom IS BEGIN p : process(x) variable r : boolean; begin for i in x'range loop y(i) <= x(i); end loop; end process; END ARCHITECTURE; use t.ba; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS signal int_x : ba(1 to 10); signal int_y : ba(1 to 10); BEGIN b : bottom port map(x => int_x, y => int_y); p : process begin int_x(1) <= true; int_x(2) <= true; int_x(3) <= true; int_x(4) <= true; int_x(5) <= true; int_x(6) <= true; int_x(7) <= true; int_x(8) <= true; int_x(9) <= true; int_x(10) <= true; wait on int_y for 10 ms; assert int_y(1) report "int_y(1)" severity failure; assert int_y(2) report "int_y(2)" severity failure; assert int_y(3) report "int_y(3)" severity failure; assert int_y(4) report "int_y(4)" severity failure; assert int_y(5) report "int_y(5)" severity failure; assert int_y(6) report "int_y(6)" severity failure; assert int_y(7) report "int_y(7)" severity failure; assert int_y(8) report "int_y(8)" severity failure; assert int_y(9) report "int_y(9)" severity failure; assert int_y(10) report "int_y(10)" severity failure; assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/event.vhdl0000664000175000017500000000154111307474416017237 0ustar potyrapotyra-- $Id: event.vhdl 4885 2009-12-08 16:04:30Z potyra $ -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is signal s : boolean; begin p : process begin -- FIXME needs proper attribute name handling. --if s = false and s'event then if s and s'event then assert false report "event" severity failure; end if; s <= true; wait on s until s'event; if not s'event then assert false report "event 2" severity failure; end if; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/proc5.vhdl0000664000175000017500000000134611137616416017150 0ustar potyrapotyra-- $Id: proc5.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is procedure foo(constant a : in string); end package t; package body t is procedure foo(constant a : in string) is begin assert false report a severity note; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process begin foo(""); foo("simulation finished"); wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/generic4.vhdl0000664000175000017500000000151211164435544017614 0ustar potyrapotyra-- $Id: generic4.vhdl 4459 2009-03-31 15:48:52Z potyra $ -- test if generics work, test generic map (composite types) -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY ewg IS GENERIC ( g1 : string := "hallo welt" ); END ENTITY ewg; ARCHITECTURE ewg_impl of ewg IS BEGIN test_ewg : process begin assert false report g1 severity note; wait; end process; END ewg_impl; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS begin -- generic must be set to default value test_ewg : ewg generic map ( g1 => "simulation finished" ); end test_bench_impl; fauhdlc-20130704/tests/icode/arrays_8.vhdl0000664000175000017500000000210011245472512017632 0ustar potyrapotyra-- $Id$ -- downto test. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is variable a : string(17 downto 10); begin x : process begin a := "76543210"; assert a(10) = '0' report "error index 10" severity failure; assert a(11) = '1' report "error index 11" severity failure; assert a(12) = '2' report "error index 12" severity failure; assert a(13) = '3' report "error index 13" severity failure; assert a(14) = '4' report "error index 14" severity failure; assert a(15) = '5' report "error index 15" severity failure; assert a(16) = '6' report "error index 16" severity failure; assert a(17) = '7' report "error index 17" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/assert1.vhdl0000664000175000017500000000141211137616416017474 0ustar potyrapotyra-- $Id: assert1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- use assertions with unconstraint arrays -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is procedure foo(constant a : in string); end package t; package body t is procedure foo(constant a : in string) is begin assert false report a severity note; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process begin foo("simulation finished"); wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/foreign_arch.vhdl0000664000175000017500000000142311207761064020540 0ustar potyrapotyra-- $Id: foreign_arch.vhdl 4519 2009-05-29 13:25:08Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY unitA IS PORT ( p1 : inout integer; p2 : in integer; p3 : out bit ); END ENTITY unitA; ARCHITECTURE impl of unitA is attribute foreign of impl : architecture is "foobar"; begin end; ENTITY unitB IS END ENTITY unitB; ARCHITECTURE implementation of unitB is SIGNAL s1 : integer; SIGNAL s2 : integer; SIGNAL s3 : bit; BEGIN instUnit : unitA PORT MAP ( p2 => s2, p1 => s1, p3 => s3 ); END implementation; fauhdlc-20130704/tests/icode/generic6.vhdl0000664000175000017500000000154411265635515017625 0ustar potyrapotyra-- $Id: generic6.vhdl 4815 2009-10-15 15:10:05Z potyra $ -- test if generics work, test generic map (composite types) -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY ewg IS GENERIC ( size : integer := 1440; g1 : string := "hallo welt" ); END ENTITY ewg; ARCHITECTURE ewg_impl of ewg IS BEGIN test_ewg : process begin assert false report g1 severity note; wait; end process; END ewg_impl; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS begin -- generic must be set to default value test_ewg : ewg generic map ( g1 => "simulation finished" ); end test_bench_impl; fauhdlc-20130704/tests/icode/attr1.vhdl0000664000175000017500000000152311137616416017150 0ustar potyrapotyra-- $Id: attr1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- attribute names test 1 -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; end package t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is variable b : byte; begin p : process begin b := "00000000"; for i in b'range loop b(i) := '1'; end loop; for j in 0 to 7 loop assert b(j) = '1' report "loop fail" severity failure; end loop; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/array_param4.vhdl0000664000175000017500000000175211137616416020503 0ustar potyrapotyra-- $Id: array_param4.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- array parameters 4 - unconstrained arrays -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range <>) of bit; procedure foo(variable a : inout byte); end package t; package body t is procedure foo(variable a : inout byte) is begin a(0) := '0'; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process variable x : bit; variable b : byte(0 to 7); begin b := "11100011"; foo(b); assert(b(0) = '0') report "foo(b) should set b(0) to '0'." severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/wait.vhdl0000664000175000017500000000214711137616416017064 0ustar potyrapotyra-- $Id: wait.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE tb of test_bench is signal s1 : boolean; signal s2 : boolean; begin p : process begin s2 <= false; wait for 100 ms; -- timeout at 100 ms s2 <= true; wait on s1 until s1; -- should be at 150ms s2 <= false; wait on s1 for 100 ms; -- timeout at 250ms s2 <= true; wait on s1 until s1 for 100 ms; -- timout at 350ms s2 <= false; wait for 10 ms; -- timeout at 360 ms s2 <= true; wait on s1 until s1 for 100 ms; -- s1 at 410 ms s2 <= false; assert false report "simulation finished" severity note; wait; end process p; p2 : process begin s1 <= false; wait for 150 ms; s1 <= true; wait for 200 ms; s1 <= false; wait for 60 ms; s1 <= true; wait; end process p2; END ARCHITECTURE tb; fauhdlc-20130704/tests/icode/attr2.vhdl0000664000175000017500000000206211137616416017150 0ustar potyrapotyra-- $Id: attr2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- unconstrained arrays and the 'range attribute. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range <>) of bit; procedure foo(variable a : inout byte); end package t; package body t is procedure foo(variable a : inout byte) is begin for i in a'range loop a(i) := '0'; end loop; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process variable x : bit; variable b : byte(0 to 7); begin b := "11111111"; foo(b); for i in b'range loop assert(b(i) = '0') report "foo(b) should set b(i) to '0'." severity failure; end loop; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/arrays_4.vhdl0000664000175000017500000000122311137616416017636 0ustar potyrapotyra-- $Id: arrays_4.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- subscribe to a driver. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; end package t; entity something is end entity something; use t.byte; architecture implementation of something is signal b : byte; begin x : process variable x : bit; begin x := '1'; b(4) <= x; end process; end implementation; fauhdlc-20130704/tests/icode/ifstats.vhdl0000664000175000017500000000145111137616416017572 0ustar potyrapotyra-- $Id: ifstats.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- mini test for the parser. will use that to test each -- new feature -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY conditions IS END ENTITY; -- -- test architecture declaration ARCHITECTURE cond_imp of conditions IS variable x : integer; variable b : boolean; BEGIN tc : process begin if 1 = 2 then null; else null; end if; if x = 2 then elsif x = 3 then null; elsif x = 4 then null; end if; if b then null; end if; end process tc; end ARCHITECTURE cond_imp; fauhdlc-20130704/tests/icode/proc_formal1.vhdl0000664000175000017500000000211111137616416020473 0ustar potyrapotyra-- $Id: proc_formal1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- generating implicit formals for procedure parameters. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range 0 to 7) of bit; procedure foo(constant a : in byte; variable b : out byte); end package t; package body t is procedure foo(constant a : in byte; variable b : out byte) is begin b := a; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process variable x : bit; variable b : byte; begin b := "00000000"; foo("11111111", b); for i in b'range loop assert(b(i) = '1') report "foo(a, b) should set b(i) to '1'." severity failure; end loop; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/loop.vhdl0000664000175000017500000000122011305246026017051 0ustar potyrapotyra-- $Id: loop.vhdl 4843 2009-12-01 17:02:14Z potyra $ -- loop w.o. until clause -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is begin p : process begin loop assert false report "looping" severity note; exit; end loop; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/for_loop.vhdl0000664000175000017500000000121111137616416017726 0ustar potyrapotyra-- $Id: for_loop.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- test a for loop -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(1 to 8) of bit; end package t; entity foo is end entity foo; use t.byte; architecture foo_impl of foo is begin bar : process variable a : byte; begin for i in 1 to 8 loop a(i) := '1'; end loop; end process bar; end architecture foo_impl; fauhdlc-20130704/tests/icode/init1.vhdl0000664000175000017500000000122611162756477017153 0ustar potyrapotyra-- $Id: init1.vhdl 4417 2009-03-26 19:53:35Z potyra $ -- test initializing of a constraint array works. -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS variable s : string(0 to 18) := "simulation finished"; begin p : process begin wait for 10 ms; assert false report s severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/array_param1.vhdl0000664000175000017500000000170411137616416020475 0ustar potyrapotyra-- $Id: array_param1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- array parameters 1 -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; function foo(constant a : byte) return bit; end package t; package body t is function foo(constant a : byte) return bit is begin return a(0); end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin x : process variable x : bit; variable b : byte; begin b := "11100011"; x := foo(b); assert(x = '1') report "foo(x) should return 1" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/array_param7.vhdl0000664000175000017500000000211211245515537020477 0ustar potyrapotyra-- $Id$ -- assign a variable of a an array to a variable of an array with a different -- direction (via a procedure) -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type b_arr is array(integer range <>) of bit; procedure assign(constant a : in b_arr; variable b : out b_arr); end package t; package body t is procedure assign(constant a : in b_arr; variable b : out b_arr) IS begin b := a; end; end; entity test_bench is end entity test_bench; use t.b_arr; architecture test_bench_impl of test_bench is variable a : b_arr(0 to 1); variable b : b_arr(100 downto 99); begin x : process begin a := "10"; t.assign(a, b); assert b(100) = '1' report "error" severity failure; assert b(99) = '0' report "error" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/proc3.vhdl0000664000175000017500000000147111137616416017145 0ustar potyrapotyra-- $Id: proc3.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is procedure foo(signal a : in boolean; variable b : in boolean); attribute foreign of foo : procedure is "foreign"; end package t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is signal int_a : boolean; variable int_b : boolean; begin p : process begin int_a <= true; int_b := false; foo(int_a, int_b); assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/tests.list0000664000175000017500000000163211457043311017267 0ustar potyrapotyra# $Id: tests.list 4965 2010-10-18 13:08:25Z potyra $ DESC="Intermediate code generator", OUTPUT="True" # ifstats arrays_1 arrays_2 arrays_3 arrays_4 arrays_5 arrays_6 arrays_7 arrays_8 records_1 funccalls_1 sig_assign1 sig_assign2 array_aggregate array_aggregate2 for_loop for_loop2 for_loop3 while_loop full_adder compinst1 wait array_param1 array_param2 array_param3 array_param4 array_param5 array_param6 array_param7 attr1 attr2 attr3 attr4 port_access port_unused array_ports array_ports2 array_ports3 array_ports4 proc1 proc2 proc3 proc4 proc5 proc6 wait_on_composite case_stat proc_formal1 proc_formal2 proc_formal3 assert1 generic1 generic2 generic3 generic4 generic5 generic6 init1 init2 init3 foreign_arch resolved1 resolved2 condal1 double_quotes loop operators OPTS="--lib ieee ../../lib/std_logic_1164.vhdl --lib work" operators2 OPTS="--lib ieee ../../lib/std_logic_1164.vhdl --lib work" event deterministic fauhdlc-20130704/tests/icode/array_param3.vhdl0000664000175000017500000000171511137616416020501 0ustar potyrapotyra-- $Id: array_param3.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- array parameters 3 -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; procedure foo(signal a : out byte); end package t; package body t is procedure foo(signal a : out byte) is begin a(0) <= '0'; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is signal x : bit; signal b : byte; begin p : process begin b <= "11100011"; wait on b; foo(b); wait on b; assert(b(0) = '0') report "foo(b) should set b(0) to '0'." severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/full_adder.vhdl0000664000175000017500000001025511137616416020220 0ustar potyrapotyra-- $Id: full_adder.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY half_adder IS PORT ( op1 : in boolean; op2 : in boolean; res : out boolean; carry : out boolean ); END ENTITY half_adder; ARCHITECTURE half_adder_impl of half_adder IS BEGIN calc_res : PROCESS (op1, op2) variable r : boolean; BEGIN r := op1 xor op2; res <= r after 10 ms; END PROCESS; calc_carry : PROCESS(op1, op2) variable r : boolean; BEGIN r := op1 and op2; carry <= r after 10 ms; END PROCESS; END ARCHITECTURE half_adder_impl; ENTITY full_adder IS PORT ( op1 : in boolean; op2 : in boolean; cin : in boolean; res : out boolean; carry : out boolean ); END ENTITY full_adder; ARCHITECTURE full_adder_impl of full_adder IS signal r1 : boolean; signal c1 : boolean; signal c2 : boolean; BEGIN -- add op1 and op2 and output to s1 a1 : half_adder port map ( op1 => op1, op2 => op2, res => r1, carry => c1 ); a2 : half_adder port map ( op1 => r1, op2 => cin, res => res, carry => c2 ); calc_cout : process(c1, c2) variable r : boolean; BEGIN r := c1 or c2; carry <= r after 10 ms; END PROCESS; END ARCHITECTURE full_adder_impl; ENTITY full_adder_sync IS PORT ( x : in boolean; y : in boolean; cin : in boolean; res : out boolean; carry : out boolean; clock : in boolean ); END ENTITY full_adder_sync; ARCHITECTURE full_adder_sync_impl of full_adder_sync IS signal res_nosync : boolean; signal carry_nosync : boolean; begin f : full_adder port map ( op1 => x, op2 => y, cin => cin, res => res_nosync, carry => carry_nosync ); p : process(clock) begin if (clock) then res <= res_nosync; carry <= carry_nosync; end if; end process; END ARCHITECTURE full_adder_sync_impl; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE tb of test_bench IS signal a1, a2, cin, res, cout, clk : boolean; BEGIN f : full_adder_sync PORT MAP ( x => a1, y => a2, cin => cin, res => res, carry => cout, clock => clk ); test : PROCESS BEGIN a1 <= true; a2 <= true; cin <= true; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = true) and (cout = true) report "(1 + 1) [1] should be 1 [1]" severity failure; a1 <= false; a2 <= false; cin <= false; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = false) and (cout = false) report "(0 + 0) [0] should be 0 [0]" severity failure; a1 <= true; a2 <= false; cin <= false; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = true) and (cout = false) report "(1 + 0) [0] should be 1 [0]" severity failure; a1 <= true; a2 <= true; cin <= false; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = false) and (cout = true) report "(1 + 1) [0] should be 0 [1]" severity failure; a1 <= false; a2 <= true; cin <= false; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = true) and (cout = false) report "(0 + 1) [0] should be 1 [0]" severity failure; a1 <= true; a2 <= false; cin <= true; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = false) and (cout = true) report "(1 + 0) [1] should be 0 [1]" severity failure; a1 <= false; a2 <= false; cin <= true; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = true) and (cout = false) report "(0 + 0) [1] should be 1 [0]" severity failure; a1 <= false; a2 <= true; cin <= true; clk <= true after 100 ms; wait on clk; clk <= false after 20 ms; wait on clk; assert (res = false) and (cout = true) report "(0 + 1) [1] should be 0 [1]" severity failure; assert false report "simulation finished" severity note; wait; END PROCESS; END ARCHITECTURE tb; fauhdlc-20130704/tests/icode/array_ports.vhdl0000664000175000017500000000207311137616416020463 0ustar potyrapotyra-- $Id: array_ports.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- check ports which are arrays of signals. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type ba is array(integer range <>) of boolean; end package; use t.ba; ENTITY bottom IS PORT ( x : in ba(1 to 10); y : out boolean ); END ENTITY bottom; ARCHITECTURE bottom_impl OF bottom IS BEGIN p : process(x) variable r : boolean; begin r := false; for i in x'range loop r := r or x(i); end loop; y <= r; end process; END ARCHITECTURE; use t.ba; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS signal int_x : ba(1 to 10); signal int_y : boolean; BEGIN b : bottom port map(x => int_x, y => int_y); p : process begin assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/resolved1.vhdl0000664000175000017500000000316311247164721020022 0ustar potyrapotyra-- $Id$ -- test resolution functions -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type bv is array(integer range <>) of boolean; function resolve_boolean_or(v : bv) return boolean; subtype boolean_or is resolve_boolean_or boolean; end package t; package body t is function resolve_boolean_or(v : bv) return boolean is begin for i in v'range loop if v(i) then return true; end if; end loop; return false; end; end; use t.boolean_or; entity d is port ( o : out boolean_or; i : in boolean ); end entity d; architecture d_impl of d is begin update_output : process(i) begin o <= i after 10 ms; end process; end; entity test_bench is end entity test_bench; use t.boolean_or; architecture test_bench_impl of test_bench is signal r : boolean_or; signal i1 : boolean; signal i2 : boolean; begin d1 : d port map(o => r, i => i1); d2 : d port map(o => r, i => i2); p : process begin i1 <= false; i2 <= false; wait for 12 ms; assert(r = false) report "r must be false" severity failure; i1 <= true; wait for 12 ms; assert(r = true) report "r must be true" severity failure; i2 <= true; wait for 12 ms; assert(r = true) report "r must be true" severity failure; i1 <= false; wait for 12 ms; assert(r = true) report "r must be true" severity failure; assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/proc_formal2.vhdl0000664000175000017500000000227411137616416020506 0ustar potyrapotyra-- $Id: proc_formal2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- generating implicit formals for procedure parameters. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range 0 to 7) of bit; function foo(constant a : in byte) return bit; end package t; package body t is function foo(constant a : in byte) return bit is variable ret : bit; begin ret := '0'; for i in a'range loop if a(i) = '1' then ret := '1'; end if; end loop; return ret; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process variable x : bit; begin x := foo("00001000"); assert(x = '1') report "foo() should return '1'." severity failure; x := foo("00000000"); assert(x = '0') report "foo() should return '0'." severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/arrays_3.vhdl0000664000175000017500000000231511137616416017640 0ustar potyrapotyra-- $Id: arrays_3.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- test for array types -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is -- shouldn't result in a type type word is array(integer range <>) of bit; -- shouldn't result in a type type memory is array(integer range <>) of word(31 downto 0); -- should result in a type type dram8k is array(0 to (8192 / 4) - 1) of word(31 downto 0); -- should result in a type type membanks is array(1 to 4) of memory(0 to (8192 / 4) - 1); end package t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin x : process variable ram : dram8k; variable ram2 : memory(0 to (256 / 4) - 1); begin for i in 1 to 10 loop ram2(i)(1) := '1'; end loop; for i in 1 to 10 loop assert ram2(i)(1) = '1' report "array assign fail" severity failure; end loop; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/sig_assign1.vhdl0000664000175000017500000000110311137616416020316 0ustar potyrapotyra-- $Id: sig_assign1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity e is end entity e; architecture a of e is signal i : integer; begin -- named process named_process : process begin i <= 1; end process named_process; -- unnamed process process begin i <= 2; end process; end a; fauhdlc-20130704/tests/icode/array_aggregate2.vhdl0000664000175000017500000000134311137616416021323 0ustar potyrapotyra-- $Id$ -- small test initializing an array of an array with an aggregate -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; type word is array(0 to 3) of byte; end package t; entity something is end entity something; use t.word; architecture implementation of something is begin x : process variable w : word; begin w := (0 => "10011001", 1 | 3 => "00010001", others => ( 4 to 7 => '0', others => '1')); end process; end implementation; fauhdlc-20130704/tests/icode/proc_formal3.vhdl0000664000175000017500000000211711137616416020503 0ustar potyrapotyra-- $Id: proc_formal3.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- generating implicit formals for procedure parameters. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range <>) of bit; procedure foo(constant a : in byte; variable b : out byte); end package t; package body t is procedure foo(constant a : in byte; variable b : out byte) is begin b := a; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process variable x : bit; variable b : byte(11 to 18); begin b := "00000000"; foo("11111111", b); for i in b'range loop assert(b(i) = '1') report "foo(a, b) should set b(i) to '1'." severity failure; end loop; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/deterministic.vhdl0000664000175000017500000000231111457043311020745 0ustar potyrapotyra-- $Id: deterministic.vhdl 4965 2010-10-18 13:08:25Z potyra $ -- test case for deterministic behaviour of driver->signal updates. -- Copyright (C) 2010 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY determin IS PORT ( a : in boolean; b : in boolean; q : out boolean ); END; ARCHITECTURE impl of determin is signal clk : boolean; signal d : boolean; signal l_clk : boolean; BEGIN andgate : process(a,b) begin clk <= a and b; end process; inverter : process(b) begin d <= not b; end process; reg : process(clk,d) begin if l_clk = false and clk = true then q <= d; end if; l_clk <= clk; end process; END; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE tb of test_bench IS signal ta, tb, tq : boolean; BEGIN d : determin PORT MAP ( a => ta, b => tb, q => tq ); test : process begin ta <= true; tb <= false; wait for 10 ms; tb <= true; wait for 10 ms; assert false report "simulation finished" severity note; wait; end process; END; fauhdlc-20130704/tests/icode/port_access.vhdl0000664000175000017500000000244311137616416020424 0ustar potyrapotyra-- $Id: port_access.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY forwarder IS PORT ( x_out : OUT integer; x_unused : OUT integer; x_in : IN integer ); END ENTITY forwarder; ARCHITECTURE forwarder_impl of forwarder IS BEGIN forward : process (x_in) BEGIN x_out <= x_in; x_unused <= x_in; END PROCESS; END ARCHITECTURE forwarder_impl; ENTITY forwarder2 IS PORT ( x_out : OUT integer; x_in : IN integer ); END ENTITY forwarder2; ARCHITECTURE forwarder2_impl of forwarder2 IS BEGIN f : forwarder PORT MAP ( x_in => x_in, x_out => x_out ); END ARCHITECTURE; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS SIGNAL x, y : integer; BEGIN f : forwarder2 port map (x_in => x, x_out => y); p : process begin x <= 1; wait on y; assert(y = 1) report "y != 1" severity failure; x <= 2; wait on y; assert(y = 2) report "y != 2" severity failure; assert false report "simulation finished." severity note; wait; end process; END ARCHITECTURE; fauhdlc-20130704/tests/icode/arrays_7.vhdl0000664000175000017500000000156411243257450017646 0ustar potyrapotyra-- $Id$ -- assign a variable of a an array to a variable of an array with a different -- direction -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type b_arr is array(integer range <>) of bit; end package t; entity test_bench is end entity test_bench; use t.b_arr; architecture test_bench_impl of test_bench is variable a : b_arr(1 to 2); variable b : b_arr(2 downto 1); begin x : process begin a := "10"; b := a; assert b(2) = '1' report "error" severity failure; assert b(1) = '0' report "error" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/records_1.vhdl0000664000175000017500000000136411137616416020001 0ustar potyrapotyra-- $Id: records_1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- small test for record types -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; type rec is record elem1 : integer; elem2 : byte; end record; end package t; entity something is end entity something; use t.rec; use t.byte; architecture implementation of something is begin x : process variable r : rec; variable b : byte; begin r.elem2 := b; r.elem1 := 1; end process; end implementation; fauhdlc-20130704/tests/icode/array_param2.vhdl0000664000175000017500000000167611137616416020506 0ustar potyrapotyra-- $Id: array_param2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- array parameters 2 -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; procedure foo(variable a : inout byte); end package t; package body t is procedure foo(variable a : inout byte) is begin a(0) := '0'; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin x : process variable x : bit; variable b : byte; begin b := "11100011"; foo(b); assert(x = '0') report "foo(b) should set b(0) to '0'." severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/array_param6.vhdl0000664000175000017500000000201711245460064020474 0ustar potyrapotyra-- $Id: array_param6.vhdl 4611 2009-08-27 10:30:12Z potyra $ -- array parameters -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(7 downto 0) of bit; function foo(constant a : byte) return bit; end package t; package body t is function foo(constant a : byte) return bit is begin return a(0); end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin x : process variable x : bit; variable b : byte; begin b := "01100011"; x := foo(b); assert(b(0) = '1') report "b(0) should be '1'" severity failure; assert(x = '1') report "foo(x) should return 1" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/generic3.vhdl0000664000175000017500000000144611164435405017615 0ustar potyrapotyra-- $Id: generic3.vhdl 4458 2009-03-31 15:47:17Z potyra $ -- test if generics work, test default value (composite types) -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY ewg IS GENERIC ( g1 : string := "simulation finished" ); END ENTITY ewg; ARCHITECTURE ewg_impl of ewg IS BEGIN test_ewg : process begin assert false report g1 severity note; wait; end process; END ewg_impl; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS begin -- generic must be set to default value test_ewg : ewg; end test_bench_impl; fauhdlc-20130704/tests/icode/attr4.vhdl0000664000175000017500000000207411137616416017155 0ustar potyrapotyra-- $Id: attr4.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- unconstrained arrays and the 'range attribute. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range <>) of bit; procedure foo(variable a : in byte); end package t; package body t is procedure foo(variable a : in byte) is variable cnt : integer; begin cnt := 0; for i in a'range loop assert false report "loop" severity note; cnt := cnt + 1; end loop; assert cnt = 8 report "cnt != 8" severity failure; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process variable x : bit; variable b : byte(0 to 7); begin b := "11111111"; foo(b); assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/proc1.vhdl0000664000175000017500000000172411137616416017144 0ustar potyrapotyra-- $Id: proc1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is procedure foo(signal a : in boolean; signal b : out boolean); end package t; package body t is procedure foo(signal a : in boolean; signal b : out boolean) is begin b <= a after 10 ms; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is signal int_a, int_b : boolean; begin p : process begin int_a <= true; int_b <= false; wait on int_a; foo(int_a, int_b); wait on int_b for 100 ms; assert int_b report "b must be true" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/case_stat.vhdl0000664000175000017500000000174711137616416020073 0ustar potyrapotyra-- $Id: case_stat.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- test for case stat with alternatives. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is BEGIN p : process variable c : integer; variable d : integer; begin c := 1; case c is when 0 => assert false report "c != 0" severity failure; d := 0; when 1 => d := 1; null; when others => d := 0; assert false report "c != 0" severity failure; end case; if d /= 1 then assert false report "case alternative not executed." severity failure; end if; assert false report "simulation finished" severity note; wait; end process p; END architecture test_bench_impl; fauhdlc-20130704/tests/icode/array_ports2.vhdl0000664000175000017500000000205211137616416020542 0ustar potyrapotyra-- $Id: array_ports2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- check ports which are arrays of signals. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type ba is array(integer range <>) of boolean; end package; use t.ba; ENTITY bottom IS PORT ( x : in ba(1 to 10); y : out ba(1 to 10) ); END ENTITY bottom; ARCHITECTURE bottom_impl OF bottom IS BEGIN p : process(x) variable r : boolean; begin for i in x'range loop y(i) <= x(i); end loop; end process; END ARCHITECTURE; use t.ba; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS signal int_x : ba(1 to 10); signal int_y : ba(1 to 10); BEGIN b : bottom port map(x => int_x, y => int_y); p : process begin assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/array_ports4.vhdl0000664000175000017500000000344611305712545020551 0ustar potyrapotyra-- $Id: array_ports4.vhdl 4853 2009-12-03 10:39:33Z potyra $ -- check ports which are arrays of signals. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type ba is array(integer range <>) of boolean; end package; use t.ba; ENTITY bottom IS PORT ( x : in ba; y : out ba(1 to 10) ); END ENTITY bottom; ARCHITECTURE bottom_impl OF bottom IS BEGIN p : process(x) variable r : boolean; begin for i in x'range loop y(i) <= x(i); end loop; end process; END ARCHITECTURE; use t.ba; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS signal int_x : ba(1 to 10); signal int_y : ba(1 to 10); BEGIN b : bottom port map(x => int_x, y => int_y); p : process begin int_x(1) <= true; int_x(2) <= true; int_x(3) <= true; int_x(4) <= true; int_x(5) <= true; int_x(6) <= true; int_x(7) <= true; int_x(8) <= true; int_x(9) <= true; int_x(10) <= true; wait on int_y for 10 ms; assert int_y(1) report "int_y(1)" severity failure; assert int_y(2) report "int_y(2)" severity failure; assert int_y(3) report "int_y(3)" severity failure; assert int_y(4) report "int_y(4)" severity failure; assert int_y(5) report "int_y(5)" severity failure; assert int_y(6) report "int_y(6)" severity failure; assert int_y(7) report "int_y(7)" severity failure; assert int_y(8) report "int_y(8)" severity failure; assert int_y(9) report "int_y(9)" severity failure; assert int_y(10) report "int_y(10)" severity failure; assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/operators2.vhdl0000664000175000017500000000134011307240670020204 0ustar potyrapotyra-- $Id: operators2.vhdl 4873 2009-12-07 17:56:08Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library ieee; use ieee.std_logic_1164.all; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS signal s : std_logic; BEGIN p : process begin s <= '1'; wait on s; s <= '1' and (not s); wait on s; assert s = '0' report "not (stdlogic)" severity failure; assert false report "simulation finished" severity note; wait; end process; END; fauhdlc-20130704/tests/icode/proc4.vhdl0000664000175000017500000000156111137616416017146 0ustar potyrapotyra-- $Id: proc4.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is procedure foo(signal a : in boolean; signal b : out boolean); end package t; package body t is procedure foo(signal a : in boolean; signal b : out boolean) is begin null; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is signal int_a, int_b : boolean; begin p : process begin int_a <= true; int_b <= false; wait on int_a; foo(int_a, int_b); assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/attr3.vhdl0000664000175000017500000000166611137616416017162 0ustar potyrapotyra-- $Id: attr3.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- small test of the "foreign" attribute. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package types is type sig_boolean is (true, false); attribute foreign of sig_boolean : type is "sig_boolean"; end package types; use types.all; entity fentity is PORT (p : in sig_boolean); attribute foreign of fentity : entity is "fentity"; end entity fentity; use types.all; entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is signal fsig : sig_boolean; begin f : fentity PORT MAP (p => fsig); x : process begin assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/array_aggregate.vhdl0000664000175000017500000000123711137616416021243 0ustar potyrapotyra-- $Id: array_aggregate.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- small test initializing an array with an aggregate -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; end package t; entity something is end entity something; use t.byte; architecture implementation of something is begin x : process variable a : byte; begin a := "10011001"; end process; end implementation; fauhdlc-20130704/tests/icode/sig_assign2.vhdl0000664000175000017500000000107211137616416020324 0ustar potyrapotyra-- $Id: sig_assign2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity e is end entity e; architecture a of e is signal i : integer; begin -- named process named_process : process variable x : integer := 0; begin i <= x; wait on i; x := i; end process named_process; end a; fauhdlc-20130704/tests/icode/wait_on_composite.vhdl0000664000175000017500000000227511137616416021644 0ustar potyrapotyra-- $Id: wait_on_composite.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- check ports which are arrays of signals. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type ba is array(integer range <>) of boolean; end package; use t.ba; ENTITY bottom IS PORT ( x : in ba(1 to 10); y : out boolean ); END ENTITY bottom; ARCHITECTURE bottom_impl OF bottom IS BEGIN p : process(x) variable r : boolean; begin r := false; for i in x'range loop r := r or x(i); end loop; y <= r after 10 ms; end process; END ARCHITECTURE; use t.ba; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS signal int_x : ba(1 to 10); signal int_y : boolean; BEGIN b : bottom port map(x => int_x, y => int_y); p : process begin int_x(5) <= true after 10 ms; wait for 100 ms; assert int_y report "int_y must be true" severity failure; assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/init3.vhdl0000664000175000017500000000141011163156435017135 0ustar potyrapotyra-- $Id: init3.vhdl 4423 2009-03-27 14:05:17Z potyra $ -- test initializing of an unconstraint array works - directly using an -- aggregate -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS constant s : string := ('s', 'i', 'm', 'u', 'l', 'a', 't', 'i', 'o', 'n', ' ', 'f', 'i', 'n', 'i', 's', 'h', 'e', 'd', '.'); begin p : process begin wait for 10 ms; assert false report s severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/arrays_5.vhdl0000664000175000017500000000226511137616416017646 0ustar potyrapotyra-- $Id: arrays_5.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- assign a signal array. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; end package t; entity test_bench is end entity test_bench; use t.byte; architecture test_bench_impl of test_bench is signal b : byte; signal a : byte; begin x : process begin a <= "11111111"; b <= "00000000"; wait on a, b; b <= a; wait on b; assert b(0) = '1' report "error" severity failure; assert b(1) = '1' report "error" severity failure; assert b(2) = '1' report "error" severity failure; assert b(3) = '1' report "error" severity failure; assert b(4) = '1' report "error" severity failure; assert b(5) = '1' report "error" severity failure; assert b(6) = '1' report "error" severity failure; assert b(7) = '1' report "error" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/arrays_2.vhdl0000664000175000017500000000227111137616416017640 0ustar potyrapotyra-- $Id: arrays_2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- small subscription test 1 -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; end package t; entity test_bench is end entity test_bench; use t.byte; architecture test_bench_impl of test_bench is begin x : process variable b : byte; variable a : byte; begin a := "00010001"; b := "11101110"; b := a; assert b(0)='0' report "array fail" severity failure; assert b(1)='0' report "array fail" severity failure; assert b(2)='0' report "array fail" severity failure; assert b(3)='1' report "array fail" severity failure; assert b(4)='0' report "array fail" severity failure; assert b(5)='0' report "array fail" severity failure; assert b(6)='0' report "array fail" severity failure; assert b(7)='1' report "array fail" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/proc6.vhdl0000664000175000017500000000627611173071401017145 0ustar potyrapotyra-- $Id: proc6.vhdl 4473 2009-04-20 13:05:05Z potyra $ -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. -- test if procedure calls from concurrent processes work as expected. package t is procedure foo(constant send : in string; constant timeout : IN time); end package t; package body t is procedure foo(constant send : in string; constant timeout : IN time) is type escapes is (NOT_ESCAPED, ESC_DIGIT_1, ESC_DIGIT_2); VARIABLE esc : escapes := NOT_ESCAPED; VARIABLE digit1 : character; begin FOR i IN send'range LOOP case esc is when NOT_ESCAPED => case send(i) is when '\' => esc := ESC_DIGIT_1; --when 'c' => -- assert false report "c" severity note; -- WAIT FOR timeout; --when 'l' => -- assert false report "l" severity note; -- WAIT FOR timeout; --when 'p' => -- assert false report "p" severity note; -- WAIT FOR timeout; --when '1' => -- assert false report "1" severity note; -- WAIT FOR timeout; --when '2' => -- assert false report "2" severity note; -- WAIT FOR timeout; when others => --assert false report send severity note; --case i is -- when 1 => -- assert false report "i=1" -- severity note; -- when 2 => -- assert false report "i=2" -- severity note; -- when 3 => -- assert false report "i=3" -- severity note; -- when 4 => -- assert false report "i=4" -- severity note; -- when others => -- assert false report "i>4" -- severity note; --end case; assert false report "unknown character" severity failure; end case; when ESC_DIGIT_1 => digit1 := send(i); esc := ESC_DIGIT_2; --assert false report "=> esc 2" severity note; when ESC_DIGIT_2 => case digit1 is when '0' => case send(i) is when '8' => -- backspace assert false report "" severity note; WAIT FOR timeout; when 'd' => -- carriage return assert false report "" severity note; WAIT FOR timeout; when others => assert false report "unknown escape" severity failure; end case; when others => assert false report "unknown escape sequence" severity failure; end case; esc := NOT_ESCAPED; --assert false report "=> not escaped" severity note; end case; END LOOP; -- sanity check case esc is when NOT_ESCAPED => null; when others => assert false report send severity note; assert false report "broken escape sequence" severity failure; end case; end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process begin wait for 10 ms; -- type sequence "\08\08\08\08\08\08" foo("\08", 100 ms); wait; end process; q : process begin wait for 10 ms; -- type sequence "\08\08\08\08\08\08" foo("\08\08\08", 100 ms); wait for 1 sec; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/port_unused.vhdl0000664000175000017500000000241711137616416020467 0ustar potyrapotyra-- $Id: port_unused.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY forwarder IS PORT ( x_out : OUT integer; x_unused : OUT integer; x_in : IN integer ); END ENTITY forwarder; ARCHITECTURE forwarder_impl of forwarder IS BEGIN forward : process (x_in) BEGIN x_out <= x_in; END PROCESS; END ARCHITECTURE forwarder_impl; ENTITY forwarder2 IS PORT ( x_out : OUT integer; x_in : IN integer ); END ENTITY forwarder2; ARCHITECTURE forwarder2_impl of forwarder2 IS BEGIN f : forwarder PORT MAP ( x_in => x_in, x_out => x_out ); END ARCHITECTURE; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS SIGNAL x, y : integer; BEGIN f : forwarder2 port map (x_in => x, x_out => y); p : process begin x <= 1; wait on y; assert(y = 1) report "y != 1" severity failure; x <= 2; wait on y; assert(y = 2) report "y != 2" severity failure; assert false report "simulation finished." severity note; wait; end process; END ARCHITECTURE; fauhdlc-20130704/tests/icode/arrays_6.vhdl0000664000175000017500000000154111243234015017630 0ustar potyrapotyra-- $Id$ -- assign a variable of a an array starting at a different index. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type b_arr is array(integer range <>) of bit; end package t; entity test_bench is end entity test_bench; use t.b_arr; architecture test_bench_impl of test_bench is variable a : b_arr(-2 to -1); variable b : b_arr(300 to 301); begin x : process begin a := "10"; b := a; assert b(300) = '1' report "error" severity failure; assert b(301) = '0' report "error" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/while_loop.vhdl0000664000175000017500000000111611137616416020254 0ustar potyrapotyra-- $Id: while_loop.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- test a while loop. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity foo is end entity foo; architecture foo_impl of foo is begin bar : process variable i : integer; begin i := 1; while i < 500 loop i := i * 2 + 3; end loop; end process bar; end architecture foo_impl; fauhdlc-20130704/tests/icode/double_quotes.vhdl0000664000175000017500000000207511263116440020762 0ustar potyrapotyra-- $Id: wait.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE tb of test_bench is begin p : process constant a : string := """"; constant b : string := "a""b"; constant c : string := "a""""b"; begin -- should be "" assert false report a severity note; assert a(0) = '"' report "double quotes 1" severity failure; -- should be a"b assert false report b severity note; --assert b(1) = '"' report "double quotes 2" severity failure; -- should be a""b --assert false report c severity note; --assert c(1) = '"' report "double quotes 3a" severity failure; --assert c(2) = '"' report "double quotes 3b" severity failure; assert false report "simulation finished" severity note; wait; end process p; END ARCHITECTURE tb; fauhdlc-20130704/tests/icode/generic2.vhdl0000664000175000017500000000166411162447227017621 0ustar potyrapotyra-- $Id: generic2.vhdl 4388 2009-03-25 15:32:39Z potyra $ -- test if generics work, test generic maps (primitive) -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY ewg IS GENERIC ( g1 : integer := 42 ); END ENTITY ewg; ARCHITECTURE ewg_impl of ewg IS BEGIN test_ewg : process begin assert g1 = 23 report "g1 must be 23" severity failure; wait; end process; END ewg_impl; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS begin -- generic must be set to default value test_ewg : ewg generic map (g1 => 23); p : process begin wait for 10 ms; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/condal1.vhdl0000664000175000017500000000170711254421167017437 0ustar potyrapotyra-- $Id$ -- test concurrent signal assignment statements -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is signal t1 : boolean; signal t2 : boolean; signal t3 : boolean; begin t1 <= true after 5 ms when t2 and t3 else false after 5 ms when (not t2) and (not t3); p : process begin t2 <= true; t3 <= true; wait for 10 ms; assert t1 report "t1 not true" severity failure; t2 <= false; wait for 10 ms; assert t1 report "t1 not true" severity failure; t3 <= false; wait for 10 ms; assert not t1 report "t1 true" severity failure; assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/init2.vhdl0000664000175000017500000000122011163156435017133 0ustar potyrapotyra-- $Id: init2.vhdl 4423 2009-03-27 14:05:17Z potyra $ -- test initializing of an unconstraint array works. -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS constant s : string := "simulation finished"; begin p : process begin wait for 10 ms; assert false report s severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/resolved2.vhdl0000664000175000017500000000406611305715047020024 0ustar potyrapotyra-- $Id$ -- test resolution functions -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type bv is array(integer range <>) of boolean; function resolve_boolean_or(v : bv) return boolean; subtype boolean_or is resolve_boolean_or boolean; type boolean_or_array is array(natural range <>) of boolean_or; end package t; package body t is function resolve_boolean_or(v : bv) return boolean is begin for i in v'range loop if v(i) then return true; end if; end loop; return false; end; end; use t.boolean_or; use t.boolean_or_array; entity d is port ( o : out boolean_or_array(0 to 1); i : in boolean ); end entity d; architecture d_impl of d is begin update_output : process(i) begin for k in o'range loop o(k) <= i after 10 ms; end loop; end process; end; entity test_bench is end entity test_bench; use t.boolean_or; use t.boolean_or_array; architecture test_bench_impl of test_bench is signal r : boolean_or_array(0 to 1); signal i1 : boolean; signal i2 : boolean; begin d1 : d port map(o => r, i => i1); d2 : d port map(o => r, i => i2); p : process begin i1 <= false; i2 <= false; wait for 12 ms; assert(r(0) = false) report "r must be false" severity failure; assert(r(1) = false) report "r must be false" severity failure; i1 <= true; wait for 12 ms; assert(r(0) = true) report "r must be true" severity failure; assert(r(1) = true) report "r must be true" severity failure; i2 <= true; wait for 12 ms; assert(r(0) = true) report "r must be true" severity failure; assert(r(1) = true) report "r must be true" severity failure; i1 <= false; wait for 12 ms; assert(r(0) = true) report "r must be true" severity failure; assert(r(1) = true) report "r must be true" severity failure; assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/icode/funccalls_1.vhdl0000664000175000017500000000162711137616416020314 0ustar potyrapotyra-- $Id: funccalls_1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- small function call test. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package funcs is function foo(a, b : integer) return integer; end package funcs; package body funcs is function foo(a, b : integer) return integer is begin return a + b; end; end; use funcs.foo; entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is begin x : process variable a, b, x : integer; begin a := 1; b := 2; x := foo(a, b); assert(x = 3) report "x != 3" severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/for_loop3.vhdl0000664000175000017500000000135711137616416020024 0ustar potyrapotyra-- $Id: for_loop3.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- test a for loop -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is begin bar : process variable a : integer; begin a := 1; for i in 1 to 2 loop a := a * 2; end loop; assert a = 4 report "wrong iteration count" severity failure; assert false report "simulation finished" severity note; wait; end process bar; end architecture test_bench_impl; fauhdlc-20130704/tests/icode/generic1.vhdl0000664000175000017500000000161711162446047017615 0ustar potyrapotyra-- $Id: generic1.vhdl 4386 2009-03-25 15:22:15Z potyra $ -- test if generics work, test default value -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY ewg IS GENERIC ( g1 : integer := 42 ); END ENTITY ewg; ARCHITECTURE ewg_impl of ewg IS BEGIN test_ewg : process begin assert g1 = 42 report "g1 must be 42" severity failure; wait; end process; END ewg_impl; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS begin -- generic must be set to default value test_ewg : ewg; p : process begin wait for 10 ms; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/array_param5.vhdl0000664000175000017500000000213711137616416020502 0ustar potyrapotyra-- $Id: array_param5.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- array parameters 5 - even more unconstrained arrays -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range <>) of bit; procedure foo(variable a : inout byte); procedure bar(variable a : inout byte); end package t; package body t is procedure foo(variable a : inout byte) is begin a(0) := '0'; end; procedure bar(variable a : inout byte) is begin foo(a); end; end t; entity test_bench is end entity test_bench; use t.all; architecture test_bench_impl of test_bench is begin p : process variable x : bit; variable b : byte(0 to 7); begin b := "11100011"; bar(b); assert(b(0) = '0') report "bar(b) should set b(0) to '0'." severity failure; assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/icode/operators.vhdl0000664000175000017500000000133711307241453020130 0ustar potyrapotyra-- $Id: operators.vhdl 4875 2009-12-07 18:02:19Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library ieee; use ieee.std_logic_1164.all; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS signal s : std_logic; BEGIN p : process begin s <= '0'; wait on s; s <= s xor '1' xor s; wait on s; assert s = '1' report "xor (stdlogic)" severity failure; assert false report "simulation finished" severity note; wait; end process; END; fauhdlc-20130704/tests/icode/for_loop2.vhdl0000664000175000017500000000126511137616416020021 0ustar potyrapotyra-- $Id: for_loop2.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- test a for loop with a next statement. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(1 to 8) of bit; end package t; entity foo is end entity foo; use t.byte; architecture foo_impl of foo is begin bar : process variable a : byte; begin for i in 1 to 8 loop next when i = 3; a(i) := '1'; end loop; end process bar; end architecture foo_impl; fauhdlc-20130704/tests/icode/generic5.vhdl0000664000175000017500000000235211214213157017606 0ustar potyrapotyra-- $Id: generic5.vhdl 4536 2009-06-11 14:36:31Z potyra $ -- test if generics work, test generic map (composite types) -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY fwg IS GENERIC ( g1 : string := "hallo welt" ); END ENTITY fwg; ARCHITECTURE fwg_impl of fwg IS BEGIN test_fwg : process begin assert false report g1 severity note; wait; end process; END fwg_impl; ENTITY ewg IS GENERIC ( g1 : string := "hallo welt" ); END ENTITY ewg; ARCHITECTURE ewg_impl of ewg IS BEGIN U : fwg generic map (g1 => g1); -- formal g1: unconstraint -- actual g1: unconstraint END ewg_impl; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS begin -- generic must be set to default value test_ewg : ewg generic map ( g1 => "simulation finished" ); -- hidden storage: "simulation finished" -- g1: unconstraint array will pass -- base pointer to hidden storage instead -- if no actual is given, use ewg initializer -- as hidden storage. end test_bench_impl; fauhdlc-20130704/tests/icode/compinst1.vhdl0000664000175000017500000000133011137616416020026 0ustar potyrapotyra-- $Id: compinst1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY unitA IS PORT ( p1 : inout integer; p2 : in integer; p3 : out bit ); END ENTITY unitA; ARCHITECTURE impl of unitA is begin end; ENTITY unitB IS END ENTITY unitB; ARCHITECTURE implementation of unitB is SIGNAL s1 : integer; SIGNAL s2 : integer; SIGNAL s3 : bit; BEGIN instUnit : unitA PORT MAP ( p2 => s2, p1 => s1, p3 => s3 ); END implementation; fauhdlc-20130704/tests/icode/arrays_1.vhdl0000664000175000017500000000121511137616416017634 0ustar potyrapotyra-- $Id: arrays_1.vhdl 4327 2009-01-27 14:41:18Z potyra $ -- small subscription test 1 -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(0 to 7) of bit; end package t; entity something is end entity something; use t.byte; architecture implementation of something is begin x : process variable x : bit; variable b : byte; begin x := b(0); end process; end implementation; fauhdlc-20130704/tests/symboltable/0000775000175000017500000000000012165333077016470 5ustar potyrapotyrafauhdlc-20130704/tests/symboltable/funccalls.vhdl0000664000175000017500000000266511137617244021331 0ustar potyrapotyra-- $Id: funccalls.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- testing function calls -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY dummy is FUNCTION foo(bofu : integer; tofu : integer) return integer is begin return bofu + tofu; end foo; end ENTITY dummy; ARCHITECTURE impl of dummy is constant failure : integer := 8; begin p1 : PROCESS variable result : integer; begin result := foo(3, 5); assert result = 8 report "3+5 != 8?" severity failure; wait; end PROCESS; p2 : PROCESS variable a, b : integer; variable result : integer; begin a := 3; b := 5; result := foo(a, b); assert result = 8 report "3+5 != 8?" severity failure; wait; end PROCESS; p3 : PROCESS variable a, b: integer; variable result : integer; begin a := 3; b := 5; result := foo(bofu => a, tofu => b); assert result = 8 report "3+5 != 8?" severity failure; wait; end PROCESS; p4 : PROCESS variable a, b: integer; variable result : integer; begin a := 3; b := 5; result := foo(tofu => b, bofu => a); -- this one should fail. --result := foo(kamefu => a, tofu => b); assert result = 8 report "3+5 != 8?" severity failure; wait; end PROCESS; end ARCHITECTURE impl; fauhdlc-20130704/tests/symboltable/iassoc.vhdl0000664000175000017500000000164111137617244020631 0ustar potyrapotyra-- $Id: iassoc.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- small test case for individual associations -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library typedefs; use typedefs.standard.all; ENTITY dummy is type iarray12 is array(1 to 2) of integer; type iarray123 is array(1 to 3) of integer; FUNCTION foo( bofu : iarray12; tofu : iarray123 ) return integer is begin return bofu(1) + tofu(2); end foo; end ENTITY dummy; ARCHITECTURE impl of dummy is begin p1 : process variable result : integer; begin -- individual association result := foo( bofu(1) => 1, bofu(2) => 2, tofu(1) => 1, tofu(2) => 2, tofu(3) => 3 ); end process; end; fauhdlc-20130704/tests/symboltable/typedefs.vhdl0000664000175000017500000000123211137617244021167 0ustar potyrapotyra-- $Id: typedefs.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- define some basic types in packages std (to be used with initially empty -- symbol table -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package standard is type BOOLEAN is (FALSE, TRUE); type BIT is ('0', '1'); type INTEGER is range 0 to 2147483647; type NATURAL is range 1 to 10; type SEVERITY_LEVEL is (note, warning, error, failure); end package standard; fauhdlc-20130704/tests/symboltable/useclauses.vhdl0000664000175000017500000000131711137617244021524 0ustar potyrapotyra-- $Id: useclauses.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- check use-clauses -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library mylib; use mylib.desc; library typedefs; use typedefs.standard.integer; Entity dummy IS signal dummy2 : integer; end Entity dummy; library typedefs; use typedefs.standard; architecture impl of dummy is signal somebool : standard.boolean; begin p : process(dummy2) begin somebool <= dummy.dummy2; end process; end architecture impl; fauhdlc-20130704/tests/symboltable/phystypes.vhdl0000664000175000017500000000153511137617244021422 0ustar potyrapotyra-- $Id: phystypes.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- test for physical types -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package types is type length is range -2147483647 to 2147483647 units mm; cm = 10 mm; m = 100 cm; km = 1000 m; inch = 254 mm; end units; end package types; entity nullentity is end entity nullentity; use types.all; architecture implementation of nullentity is begin x : process variable foo : length; variable bar : length; begin foo := 48 mm; bar := 2 * foo + 3 cm; foo := bar - 5 km; bar := foo + 100 inch; end process; end implementation; fauhdlc-20130704/tests/symboltable/attributes.vhdl0000664000175000017500000000120611137617244021533 0ustar potyrapotyra-- $Id: attributes.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- small test case for attributes. -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library typedefs; use typedefs.standard.all; Entity desc IS signal foo : integer; END Entity desc; architecture implementation of desc is signal bar : integer; begin P : process begin wait until foo'event; bar <= foo'quiet(4); end process P; end desc; fauhdlc-20130704/tests/symboltable/tests.list0000664000175000017500000000052211073361302020513 0ustar potyrapotyra# $Id: tests.list 3279 2008-10-09 10:53:54Z potyra $ DESC="Symboltable", COMMON_OPTS="--parse-only" # test cases: typedefs ifstat std_logic_1164 nested selnames useclauses OPTS="--lib=typedefs typedefs.vhdl --lib=mylib nested.vhdl --lib=work" funccalls phystypes arrays stdlogic OPTS="--lib=ieee std_logic_1164.vhdl --lib=work" functions fauhdlc-20130704/tests/symboltable/stdlogic.vhdl0000664000175000017500000010320511137617244021157 0ustar potyrapotyra-- $Id: stdlogic.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- vim:tabstop=8:shiftwidth=8:textwidth=72 -- VHDL-testbench for ieee.std_logic_1164 (FAUmachine's own hacked -- version, not the IEEE one) -- -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library ieee; use ieee.std_logic_1164.ALL; entity foo is port ( signal std_vec_in : in std_logic_vector(1 to 32); signal std_vec_out : out std_logic_vector(1 to 32) ); end entity foo; architecture foos of foo is begin catcher : process BEGIN wait on std_vec_in; ASSERT FALSE REPORT "event on std_vec_in" SEVERITY NOTE; std_vec_out(1) <= 'L'; END PROCESS catcher; end architecture foos; library ieee; use ieee.std_logic_1164.ALL; entity node is port ( signal std_vec_out : out std_logic_vector(1 to 32); signal std_vec_in : in std_logic_vector(1 to 32) ); signal dummy : boolean; end entity node; architecture structural of node is begin bar : foo port map ( std_vec_in => std_vec_out, std_vec_out => std_vec_in ); test_stdlogic : PROCESS VARIABLE o1 : std_logic; VARIABLE o2 : std_logic; VARIABLE result : std_logic; VARIABLE stdvec : std_logic_vector(23 to 42); VARIABLE b : integer; VARIABLE stdvec32 : std_logic_vector(1 to 32); BEGIN -- **************************************************** -- ** OR ** -- **************************************************** ASSERT false REPORT "testing std_logic: or" SEVERITY NOTE; -- U against others o1 := 'U'; o2 := 'U'; result := o1 or o2; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := 'X'; result := o1 or o2; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := '0'; result := o1 or o2; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := '1'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := 'Z'; result := o1 or o2; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := 'W'; result := o1 or o2; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := 'L'; result := o1 or o2; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'U'; o2 := '-'; result := o1 or o2; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'U' REPORT "or" SEVERITY FAILURE; -- X against others (w.o. U) o1 := 'X'; o2 := 'X'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'X'; o2 := '0'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'X'; o2 := '1'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'X'; o2 := 'Z'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'X'; o2 := 'W'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'X'; o2 := 'L'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'X'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'X'; o2 := '-'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; -- 0 against others (w.o. U, X) o1 := '0'; o2 := '0'; result := o1 or o2; ASSERT result = '0' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '0' REPORT "or" SEVERITY FAILURE; o1 := '0'; o2 := '1'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := '0'; o2 := 'Z'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := '0'; o2 := 'W'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := '0'; o2 := 'L'; result := o1 or o2; ASSERT result = '0' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '0' REPORT "or" SEVERITY FAILURE; o1 := '0'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := '0'; o2 := '-'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; -- 1 against others (w.o. U, X, 0) o1 := '1'; o2 := '1'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := '1'; o2 := 'Z'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := '1'; o2 := 'W'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := '1'; o2 := 'L'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := '1'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := '1'; o2 := '-'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; -- Z against others (w.o. U, X, 0, 1) o1 := 'Z'; o2 := 'Z'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'Z'; o2 := 'W'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'Z'; o2 := 'L'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'Z'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'Z'; o2 := '-'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; -- W against others (w.o. U, X, 0, 1, Z) o1 := 'W'; o2 := 'W'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'W'; o2 := 'L'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; o1 := 'W'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'W'; o2 := '-'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; -- L against others (w.o. U, X, 0, 1, Z, W) o1 := 'L'; o2 := 'L'; result := o1 or o2; ASSERT result = '0' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '0' REPORT "or" SEVERITY FAILURE; o1 := 'L'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'L'; o2 := '-'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; -- H against others (w.o. U, X, 0, 1, Z, W, L) o1 := 'H'; o2 := 'H'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; o1 := 'H'; o2 := '-'; result := o1 or o2; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = '1' REPORT "or" SEVERITY FAILURE; -- - against others (w.o. U, X, 0, 1, Z, W, L, H) o1 := '-'; o2 := '-'; result := o1 or o2; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; result := o2 or o1; ASSERT result = 'X' REPORT "or" SEVERITY FAILURE; -- **************************************************** -- ** AND ** -- **************************************************** ASSERT false REPORT "testing std_logic: and" SEVERITY NOTE; -- U against others o1 := 'U'; o2 := 'U'; result := o1 and o2; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := 'X'; result := o1 and o2; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := '0'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := '1'; result := o1 and o2; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := 'Z'; result := o1 and o2; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := 'W'; result := o1 and o2; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := 'L'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := 'H'; result := o1 and o2; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; o1 := 'U'; o2 := '-'; result := o1 and o2; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'U' REPORT "and" SEVERITY FAILURE; -- X against others (w.o. U) o1 := 'X'; o2 := 'X'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'X'; o2 := '0'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'X'; o2 := '1'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'X'; o2 := 'Z'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'X'; o2 := 'W'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'X'; o2 := 'L'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'X'; o2 := 'H'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'X'; o2 := '-'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; -- 0 against others (w.o. U, X) o1 := '0'; o2 := '0'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := '0'; o2 := '1'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := '0'; o2 := 'Z'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := '0'; o2 := 'W'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := '0'; o2 := 'L'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := '0'; o2 := 'H'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := '0'; o2 := '-'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; -- 1 against others (w.o. U, X, 0) o1 := '1'; o2 := '1'; result := o1 and o2; ASSERT result = '1' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '1' REPORT "and" SEVERITY FAILURE; o1 := '1'; o2 := 'Z'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := '1'; o2 := 'W'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := '1'; o2 := 'L'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := '1'; o2 := 'H'; result := o1 and o2; ASSERT result = '1' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '1' REPORT "and" SEVERITY FAILURE; o1 := '1'; o2 := '-'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; -- Z against others (w.o. U, X, 0, 1) o1 := 'Z'; o2 := 'Z'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'Z'; o2 := 'W'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'Z'; o2 := 'L'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'Z'; o2 := 'H'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'Z'; o2 := '-'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; -- W against others (w.o. U, X, 0, 1, Z) o1 := 'W'; o2 := 'W'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'W'; o2 := 'L'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'W'; o2 := 'H'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; o1 := 'W'; o2 := '-'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; -- L against others (w.o. U, X, 0, 1, Z, W) o1 := 'L'; o2 := 'L'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'L'; o2 := 'H'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; o1 := 'L'; o2 := '-'; result := o1 and o2; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '0' REPORT "and" SEVERITY FAILURE; -- H against others (w.o. U, X, 0, 1, Z, W, L) o1 := 'H'; o2 := 'H'; result := o1 and o2; ASSERT result = '1' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = '1' REPORT "and" SEVERITY FAILURE; o1 := 'H'; o2 := '-'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; -- - against others (w.o. U, X, 0, 1, Z, W, L, H) o1 := '-'; o2 := '-'; result := o1 and o2; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; result := o2 and o1; ASSERT result = 'X' REPORT "and" SEVERITY FAILURE; -- **************************************************** -- ** XOR ** -- **************************************************** ASSERT false REPORT "testing std_logic: XOR" SEVERITY NOTE; -- U against others o1 := 'U'; o2 := 'U'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := 'X'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := '0'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := '1'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := 'Z'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := 'W'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := 'L'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := 'H'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; o1 := 'U'; o2 := '-'; result := o1 xor o2; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'U' REPORT "xor" SEVERITY FAILURE; -- X against others (w.o. U) o1 := 'X'; o2 := 'X'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'X'; o2 := '0'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'X'; o2 := '1'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'X'; o2 := 'Z'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'X'; o2 := 'W'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'X'; o2 := 'L'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'X'; o2 := 'H'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'X'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- 0 against others (w.o. U, X) o1 := '0'; o2 := '0'; result := o1 xor o2; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; o1 := '0'; o2 := '1'; result := o1 xor o2; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; o1 := '0'; o2 := 'Z'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := '0'; o2 := 'W'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := '0'; o2 := 'L'; result := o1 xor o2; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; o1 := '0'; o2 := 'H'; result := o1 xor o2; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; o1 := '0'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- 1 against others (w.o. U, X, 0) o1 := '1'; o2 := '1'; result := o1 xor o2; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; o1 := '1'; o2 := 'Z'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := '1'; o2 := 'W'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := '1'; o2 := 'L'; result := o1 xor o2; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; o1 := '1'; o2 := 'H'; result := o1 xor o2; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; o1 := '1'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- Z against others (w.o. U, X, 0, 1) o1 := 'Z'; o2 := 'Z'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'Z'; o2 := 'W'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'Z'; o2 := 'L'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'Z'; o2 := 'H'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'Z'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- W against others (w.o. U, X, 0, 1, Z) o1 := 'W'; o2 := 'W'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'W'; o2 := 'L'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'W'; o2 := 'H'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; o1 := 'W'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- L against others (w.o. U, X, 0, 1, Z, W) o1 := 'L'; o2 := 'L'; result := o1 xor o2; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; o1 := 'L'; o2 := 'H'; result := o1 xor o2; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '1' REPORT "xor" SEVERITY FAILURE; o1 := 'L'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- H against others (w.o. U, X, 0, 1, Z, W, L) o1 := 'H'; o2 := 'H'; result := o1 xor o2; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = '0' REPORT "xor" SEVERITY FAILURE; o1 := 'H'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- - against others (w.o. U, X, 0, 1, Z, W, L, H) o1 := '-'; o2 := '-'; result := o1 xor o2; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; result := o2 xor o1; ASSERT result = 'X' REPORT "xor" SEVERITY FAILURE; -- **************************************************** -- ** NOT ** -- **************************************************** ASSERT false REPORT "testing std_logic: NOT" SEVERITY NOTE; o1 := 'U'; result := not o1; ASSERT result = 'U' REPORT "not" SEVERITY FAILURE; o1 := 'X'; result := not o1; ASSERT result = 'X' REPORT "not" SEVERITY FAILURE; o1 := '0'; result := not o1; ASSERT result = '1' REPORT "not" SEVERITY FAILURE; o1 := '1'; result := not o1; ASSERT result = '0' REPORT "not" SEVERITY FAILURE; o1 := 'Z'; result := not o1; ASSERT result = 'X' REPORT "not" SEVERITY FAILURE; o1 := 'W'; result := not o1; ASSERT result = 'X' REPORT "not" SEVERITY FAILURE; o1 := 'L'; result := not o1; ASSERT result = '1' REPORT "not" SEVERITY FAILURE; o1 := 'H'; result := not o1; ASSERT result = '0' REPORT "not" SEVERITY FAILURE; o1 := '-'; result := not o1; ASSERT result = 'X' REPORT "not" SEVERITY FAILURE; -- **************************************************** -- ** AGGREGATES ** -- **************************************************** assert false REPORT "testing aggregates" SEVERITY NOTE; stdvec := (27 => 'H', 32 => 'L', others => 'Z'); assert stdvec(23) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(24) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(25) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(26) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(27) = 'H' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(28) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(29) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(30) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(31) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(32) = 'L' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(33) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(34) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(35) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(36) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(37) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(38) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(39) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(40) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(41) = 'Z' REPORT "aggregates" SEVERITY FAILURE; assert stdvec(42) = 'Z' REPORT "aggregates" SEVERITY FAILURE; -- the following should be valid vhdl, but it isn't -- thus, I cannot test aggregates of aggregates -- stdvecvec = (others => (others => 'Z')); -- **************************************************** -- ** CONVERSION ** -- **************************************************** assert false REPORT "testing conversion" SEVERITY NOTE; o1 := 'H'; to_bit(o1, 0, b); ASSERT b = 1 REPORT "conversion" SEVERITY FAILURE; stdvec32 := (1 => '1', 4 => '1', 7 => '1', 13 => '1', 20=> '1', 30 => '1', others => '0'); to_bit_vector32(stdvec32, 0, b); ASSERT b = 537399369 REPORT "conversion" SEVERITY FAILURE; stdvec32 := (1 => 'H', 2 => 'L', 3 => 'H', 4 => 'H', others => 'L'); to_bit_vector32(stdvec32, 0, b); ASSERT b = 13 REPORT "conversion" SEVERITY FAILURE; -- **************************************************** -- ** CONVERSION (2) ** -- **************************************************** assert false REPORT "testing conversion back" SEVERITY NOTE; -- convert some deadbeaf :) b := -559038801; to_stdlogic_vector32(b, stdvec32); -- 'f' ASSERT stdvec32(1) = '1' REPORT "conversion2-b0" SEVERITY FAILURE; ASSERT stdvec32(2) = '1' REPORT "conversion2-b1" SEVERITY FAILURE; ASSERT stdvec32(3) = '1' REPORT "conversion2-b2" SEVERITY FAILURE; ASSERT stdvec32(4) = '1' REPORT "conversion2-b3" SEVERITY FAILURE; --'a' ASSERT stdvec32(5) = '0' REPORT "conversion2-b4" SEVERITY FAILURE; ASSERT stdvec32(6) = '1' REPORT "conversion2-b5" SEVERITY FAILURE; ASSERT stdvec32(7) = '0' REPORT "conversion2-b6" SEVERITY FAILURE; ASSERT stdvec32(8) = '1' REPORT "conversion2-b7" SEVERITY FAILURE; --'e' ASSERT stdvec32(9) = '0' REPORT "conversion2-b8" SEVERITY FAILURE; ASSERT stdvec32(10) = '1' REPORT "conversion2-b9" SEVERITY FAILURE; ASSERT stdvec32(11) = '1' REPORT "conversion2-b10" SEVERITY FAILURE; ASSERT stdvec32(12) = '1' REPORT "conversion2-b11" SEVERITY FAILURE; --'b' ASSERT stdvec32(13) = '1' REPORT "conversion2-b12" SEVERITY FAILURE; ASSERT stdvec32(14) = '1' REPORT "conversion2-b13" SEVERITY FAILURE; ASSERT stdvec32(15) = '0' REPORT "conversion2-b14" SEVERITY FAILURE; ASSERT stdvec32(16) = '1' REPORT "conversion2-b15" SEVERITY FAILURE; -- 'd' ASSERT stdvec32(17) = '1' REPORT "conversion2-b16" SEVERITY FAILURE; ASSERT stdvec32(18) = '0' REPORT "conversion2-b17" SEVERITY FAILURE; ASSERT stdvec32(19) = '1' REPORT "conversion2-b18" SEVERITY FAILURE; ASSERT stdvec32(20) = '1' REPORT "conversion2-b19" SEVERITY FAILURE; --'a' ASSERT stdvec32(21) = '0' REPORT "conversion2-b20" SEVERITY FAILURE; ASSERT stdvec32(22) = '1' REPORT "conversion2-b21" SEVERITY FAILURE; ASSERT stdvec32(23) = '0' REPORT "conversion2-b22" SEVERITY FAILURE; ASSERT stdvec32(24) = '1' REPORT "conversion2-b23" SEVERITY FAILURE; --'e' ASSERT stdvec32(25) = '0' REPORT "conversion2-b24" SEVERITY FAILURE; ASSERT stdvec32(26) = '1' REPORT "conversion2-b25" SEVERITY FAILURE; ASSERT stdvec32(27) = '1' REPORT "conversion2-b26" SEVERITY FAILURE; ASSERT stdvec32(28) = '1' REPORT "conversion2-b27" SEVERITY FAILURE; --'d' ASSERT stdvec32(29) = '1' REPORT "conversion2-b28" SEVERITY FAILURE; ASSERT stdvec32(30) = '0' REPORT "conversion2-b29" SEVERITY FAILURE; ASSERT stdvec32(31) = '1' REPORT "conversion2-b30" SEVERITY FAILURE; ASSERT stdvec32(32) = '1' REPORT "conversion2-b31" SEVERITY FAILURE; -- **************************************************** -- ** SIGNAL ASSIGNMENT (VECTOR) ** -- **************************************************** ASSERT false REPORT "testing std_logic: array signal assignment" SEVERITY NOTE; std_vec_out <= stdvec32; wait on std_vec_in; ASSERT false REPORT "got event back. good." SEVERITY NOTE; ASSERT std_vec_in(1) = 'L' REPORT "signal assignement (vector)" SEVERITY FAILURE; -- **************************************************** -- ** GENERAL SANITY ** -- **************************************************** --ASSERT false REPORT "testing std_logic: illegal assign" --SEVERITY NOTE; --o1 := 'a'; --o2 := 'F'; --ASSERT false REPORT "The last test should have failed." --SEVERITY failure; wait on dummy; END PROCESS test_stdlogic; end architecture structural; fauhdlc-20130704/tests/symboltable/nested.vhdl0000664000175000017500000000117111137617244020630 0ustar potyrapotyra-- $Id: nested.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. Entity desc IS signal foo : integer; END Entity desc; architecture implementation of desc is signal bar : integer; function myFunc(x : integer) return integer is variable bar : integer; -- homograph to imp.bar begin foo <= bar; foo <= x + bar; return 0; end; begin end desc; fauhdlc-20130704/tests/symboltable/functions.vhdl0000664000175000017500000000236411137617244021363 0ustar potyrapotyra-- $Id: functions.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- test for some different arrays -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity nullentity is end entity nullentity; architecture implementation of nullentity is type R1 is record I: integer; end record; type unconarraytype is array(integer range <>) of r1; type integer_array is array(1 to 10) of integer; function bar(x : integer; y : integer) return integer; function bar(x : unconarraytype(5 to 16)) return R1; function bar(x : unconarraytype(5 to 16)) return integer_array; function f return r1; function f(x : R1) return R1; function bar(f : integer range 4 to 18) return R1; begin p : process variable v1, v2, v3 : integer; begin v1 := bar(4); v2 := bar(4).i; v3 := bar(x => 4); v1 := bar(y => 4, x => 5); v2 := bar(x => bar(4)); v3 := bar(v1, y => bar(bar(4))(5)); -- valid! v1 := f.i; -- call f and do selection to i. v1 := f(x.i => v2); v2 := f(x.i => v2).i; end process; end implementation; fauhdlc-20130704/tests/symboltable/std_logic_1164.vhdl0000664000175000017500000001623611137617244022000 0ustar potyrapotyra-- $Id: std_logic_1164.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- this is not what you'd expect, but rather FAUmachine's own hacked -- std_logic_1164 implementation. At least it makes a test-case :). -- -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. PACKAGE std_logic_1164 IS TYPE std_logic IS ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'); TYPE std_logic_vector IS array ( integer range <> ) of std_logic; -- FIXME: functions don't work yet :( -- FIXME2: std_logic vs std_ulogic --FUNCTION to_bit (CONSTANT s : IN std_logic; -- CONSTANT xmap : IN bit := '0') --RETURN bit; -- this is really a dirty hack! PROCEDURE to_bit(s : IN std_logic; xmap: IN integer; result : out integer); --FIXME: we really want this... --function to_bitvector (constant s : in std_logic_vector; -- constant xmap : in bit := '0') -- return bit_vector; -- but we get currently only this PROCEDURE to_bit_vector32(s : in std_logic_vector(1 to 32); xmap : in integer; result : integer); --FIXME same as above --function to_stdlogicvector (constant b : in bit_vector) -- return std_logic_vector; -- convert s to result PROCEDURE to_stdlogic_vector32(s : in integer; result : out std_logic_vector(1 to 32) ); -- these shouldn't exist at all PROCEDURE to_stdlogic_vector31(s : in integer; result : out std_logic_vector(31 downto 0) ); PROCEDURE to_stdlogic_vector3(s : in integer; result : out std_logic_vector(31 downto 0) ); PROCEDURE to_bit_vector31(s : in std_logic_vector(31 downto 0); xmap : in integer; result : integer); PROCEDURE to_bit_vector3(s : in std_logic_vector(3 downto 0); xmap : in integer; result : integer); PROCEDURE resolve_1 (s1 : in std_logic; s2 : in std_logic; r : out std_logic); END PACKAGE std_logic_1164; PACKAGE BODY std_logic_1164 IS --FUNCTION to_bit (CONSTANT s : IN std_logic; -- CONSTANT xmap : IN bit := '0') -- RETURN bit IS --BEGIN -- if ((s = '1') or (s = 'H')) then -- return 1; -- else -- if (s = '0') or (s = 'L') then -- return 0; -- else -- return xmap; -- end if; -- end if; --END to_bit; PROCEDURE to_bit(s : IN std_logic; xmap: IN integer; result : out integer) IS BEGIN if ((s = '1') or (s = 'H')) then result := 1; else if (s = '0') or (s = 'L') then result := 0; else result := xmap; end if; end if; END to_bit; PROCEDURE to_bit_vector32(s : in std_logic_vector(1 to 32); xmap : in integer; result : integer) IS VARIABLE i : integer; VARIABLE m : integer := 1; BEGIN result := 0; FOR i IN 1 to 32 loop CASE s(i) IS WHEN 'H' => result := result or m; WHEN '1' => result := result or m; WHEN '0' => -- don't do anything here :) result := result; WHEN 'L' => -- don't do anything here :) result := result; WHEN others => result := result or (m * xmap); END CASE; m := m * 2; END loop; END to_bit_vector32; PROCEDURE to_stdlogic_vector32(s : in integer; result : out std_logic_vector(1 to 32) ) is VARIABLE i : integer; VARIABLE m : integer := 1; BEGIN for i in 1 to 32 loop if (s and m) = m then result(i) := '1'; else result(i) := '0'; end if; m := m * 2; END loop; END to_stdlogic_vector32; PROCEDURE to_stdlogic_vector31(s : in integer; result : out std_logic_vector(31 downto 0) ) is VARIABLE i : integer; VARIABLE m : integer := 1; BEGIN for i in 0 to 31 loop if (s and m) = m then result(i) := '1'; else result(i) := '0'; end if; m := m * 2; END loop; END to_stdlogic_vector31; PROCEDURE to_stdlogic_vector3(s : in integer; result : out std_logic_vector(3 downto 0) ) is VARIABLE i : integer; VARIABLE m : integer := 1; BEGIN for i in 0 to 3 loop if (s and m) = m then result(i) := '1'; else result(i) := '0'; end if; m := m * 2; END loop; END to_stdlogic_vector3; PROCEDURE to_bit_vector31(s : in std_logic_vector(31 downto 0); xmap : in integer; result : integer) IS VARIABLE i : integer; VARIABLE m : integer := 1; BEGIN result := 0; FOR i IN 0 to 31 loop CASE s(i) IS WHEN 'H' => result := result or m; WHEN '1' => result := result or m; WHEN '0' => -- don't do anything here :) result := result; WHEN 'L' => -- don't do anything here :) result := result; WHEN others => result := result or (m * xmap); END CASE; m := m * 2; END loop; END to_bit_vector31; PROCEDURE to_bit_vector3(s : in std_logic_vector(3 downto 0); xmap : in integer; result : integer) IS VARIABLE i : integer; VARIABLE m : integer := 1; BEGIN result := 0; FOR i IN 0 to 3 loop CASE s(i) IS WHEN 'H' => result := result or m; WHEN '1' => result := result or m; WHEN '0' => -- don't do anything here :) result := result; WHEN 'L' => -- don't do anything here :) result := result; WHEN others => result := result or (m * xmap); END CASE; m := m * 2; END loop; END to_bit_vector3; PROCEDURE resolve_1 (signal s1 : in std_logic; signal s2 : in std_logic; signal r : out std_logic) IS BEGIN if (s1 = 'U') or (s2 = 'U') then r := 'U'; elsif (s1 = 'X') or (s2 = 'X') then r := 'X'; else case s1 is when '0' => case s2 is when '0' => r := '0'; when '1' => r := 'X'; when 'Z' => r := '0'; when 'W' => r := '0'; when 'L' => r := '0'; when 'H' => r := '0'; when '-' => r := 'X'; end case; when '1' => case s2 is when '0' => r := 'X'; when '1' => r := '1'; when 'Z' => r := '1'; when 'W' => r := '1'; when 'L' => r := '1'; when 'H' => r := '1'; when '-' => r := 'X'; end case; when 'Z' => case s2 is when '0' => r := '0'; when '1' => r := '1'; when 'Z' => r := 'Z'; when 'W' => r := 'W'; when 'L' => r := 'L'; when 'H' => r := 'H'; when '-' => r := 'X'; end case; when 'W' => case s2 is when '0' => r := '0'; when '1' => r := '1'; when 'W' => r := 'W'; when 'W' => r := 'W'; when 'W' => r := 'W'; when 'W' => r := 'W'; when 'X' => r := 'X'; end case; when 'L' => case s2 is when '0' => r := '0'; when '1' => r := '1'; when 'L' => r := 'L'; when 'W' => r := 'W'; when 'L' => r := 'L'; when 'W' => r := 'W'; when 'X' => r := 'X'; end case; when 'H' => case s2 is when '0' => r := '0'; when '1' => r := '1'; when 'L' => r := 'H'; when 'W' => r := 'W'; when 'L' => r := 'W'; when 'W' => r := 'H'; when 'X' => r := 'X'; end case; when '-' => r := 'X'; end case; end if; END resolve_1; END std_logic_1164; fauhdlc-20130704/tests/symboltable/ifstat.vhdl0000664000175000017500000000265711137617244020652 0ustar potyrapotyra-- $Id: ifstat.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- test if-stat parsing with a number of different if-stats. -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity iftest is type depressed_bool is (eventually, unlikely); type tiny is range 0 to 100; END ENTITY; ARCHITECTURE ifarch of iftest IS variable result : tiny; variable c1, c2, c3, c3b, c4, c4b, c5, c5b : depressed_bool; variable c5c, c6, c6b, c6c : depressed_bool; BEGIN testIfs : process begin -- trivial 1 if c1 then result := 1; end if; -- trivial 2 if c2 then result := 2; else result := 3; end if; -- one elsif present, no else if c3 then result := 4; elsif c3b then result := 5; end if; -- one elsif present, else present as well. if c4 then result := 6; elsif c4b then result := 7; else result := 8; end if; -- two elsifs present, no else if c5 then result := 9; elsif c5b then result := 10; elsif c5c then result := 11; end if; -- two elsifs present, else as well. if c6 then result := 12; elsif c6b then result := 13; elsif c6c then result := 14; else result := 15; end if; end process testIfs; END ARCHITECTURE ifarch; fauhdlc-20130704/tests/symboltable/arrays.vhdl0000664000175000017500000000255511137617244020656 0ustar potyrapotyra-- $Id: arrays.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- test for some different arrays -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library std; use std.standard.all; package types is type word is array(0 to 31) of bit; type bitarray is array(INTEGER range <>) of bit; type memory is array(INTEGER range <>, INTEGER range <>) of bit; subtype small is integer range 0 to 127; --type memory3 is array(small, 0 to 31) of bit; type memory2 is array(small, 0 to 31) of bit; type memory3 is array(0 to 127, 0 to 31) of bit; end package types; use types.all; entity nullentity is end entity nullentity; architecture implementation of nullentity is begin x : process constant memsize : integer := 127; variable foo : word; -- no index constrained allowed here! variable bar : memory(0 to memsize); variable tofu : memory(small); variable test : memory( 16 to 4, 5 to 8 ); variable bla : integer range 1 to 112; constant foobar -- comment in identifier list : bitarray := "11110000"; -- (0 to 7) begin bar(4, 5) := '1'; bar(0) := "0"; tofu(0, 0) := '1'; tofu(0, 1) := '0'; end process; end implementation; fauhdlc-20130704/tests/symboltable/selnames.vhdl0000664000175000017500000000273711137617244021166 0ustar potyrapotyra-- $Id: selnames.vhdl 4329 2009-01-27 14:48:04Z potyra $ -- test for various different kinds of selected names. -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package outer2 is signal foo : integer; end package outer2; entity outer1 is signal foo : integer; type R1 is record elem1 : integer; elem2 : integer; end record; type R2 is record elem1 : integer; elem2 : R1; end record; type R3 is record elem1 : R1; elem2 : R2; end record; end entity outer1; architecture inner of outer1 is function foo (foobar : integer) return integer is begin return - foobar; end; begin p1 : process variable foo : integer; variable bar : std.standard.boolean; variable vr1 : r1; variable vr2 : r2; variable vr3 : r3; begin wait on outer1.foo; foo := 2; p1.foo := 3; outer1.foo <= 4; outer2.foo <= 5; work.outer2.foo <= 6; --inner.foo <= 7; -- doesn't make sense. inner.p1.foo := 9; foo := vr1.elem1; foo := vr1.elem2; foo := vr2.elem1; foo := vr2.elem2.elem1; foo := vr2.elem2.elem2; --foo := vr3.elem1; -- error here! foo := vr3.elem1.elem1; foo := vr3.elem1.elem2; foo := vr3.elem2.elem1; foo := vr3.elem2.elem2.elem1; foo := vr3.elem2.elem2.elem2; end process p1; end architecture inner; fauhdlc-20130704/tests/error_tests/0000775000175000017500000000000012165333076016525 5ustar potyrapotyrafauhdlc-20130704/tests/error_tests/port_visibility.vhdl0000664000175000017500000000103611137616037022636 0ustar potyrapotyra-- $Id: port_visibility.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- check if visibility of a port hides a type with the same name. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is PORT (boolean : in boolean; something : out boolean); -- @ERROR@ Parse error end entity test_bench; fauhdlc-20130704/tests/error_tests/while_false.vhdl0000664000175000017500000000153611137616037021672 0ustar potyrapotyra-- $Id: while_false.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- test a for while loop with a constant false condition. -- this will "only" produce a warning, so it should be executed with -Werror -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is begin p : process begin while 41 - 5 * 8 > 100 / (5 + 5) loop -- @ERROR@ While-loop will assert false report "cannot reach loop." severity failure; end loop; assert false report "simulation finished" severity note; wait; end process p; end architecture test_bench_impl; fauhdlc-20130704/tests/error_tests/attr_type.vhdl0000664000175000017500000000175311137616037021424 0ustar potyrapotyra-- $Id: attr_type.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- small test of the "foreign" attribute, with two type errors -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package types is type sig_boolean is (true, false); attribute foreign of sig_boolean : type is 1; -- @ERROR@ Type error end package types; use types.all; entity fentity is PORT (p : in sig_boolean); attribute foreign of fentity : entity is false; -- @ERROR@ Type error end entity fentity; use types.all; entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is signal fsig : sig_boolean; begin f : fentity PORT MAP (p => fsig); x : process begin assert false report "simulation finished" severity note; wait; end process; end test_bench_impl; fauhdlc-20130704/tests/error_tests/for_loop.vhdl0000664000175000017500000000161711137616037021227 0ustar potyrapotyra-- $Id: for_loop.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- test a for loop, and if non-fitting next statements are found. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(1 to 8) of bit; end package t; entity foo is end entity foo; use t.byte; architecture foo_impl of foo is begin bar : process variable a : byte; variable fabar : integer; -- tricky preseed the name begin next when a(2) = '1'; -- @ERROR@ Next/Exit statement not within a loop statement. fubar : for i in 1 to 8 loop a(i) := '1'; next fabar; -- @ERROR@ Missing loop statement with label . end loop; end process bar; end architecture foo_impl; fauhdlc-20130704/tests/error_tests/tests.list0000664000175000017500000000053611307673414020570 0ustar potyrapotyra# $Id: tests.list 4888 2009-12-09 10:08:12Z potyra $ DESC="Check for various compile errors", OUTPUT="True" # selnames compinst1 array_wrong_indices array_wrong_indices2 test_indices proc_wait proc_wait2 attr_type while_false OPTS="-Werror" port_visibility port_unused OPTS="-Werror" types OPTS="--lib ieee ../../lib/std_logic_1164.vhdl --lib work" fauhdlc-20130704/tests/error_tests/proc_wait.vhdl0000664000175000017500000000124511137616037021374 0ustar potyrapotyra-- $Id: proc_wait.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- a process with a sensitivity list mustn't contain a wait statement. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity something is end entity something; architecture implementation of something is signal s : integer; begin x : process(s) variable a : integer; begin a := 1; wait on s; -- @ERROR@ Wait statement and sensitivity end process; end implementation; fauhdlc-20130704/tests/error_tests/test_indices.vhdl0000664000175000017500000000247111137616037022064 0ustar potyrapotyra-- $Id: test_indices.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- type resolution for function calls returning arrays and its index -- constraints. Only the prefix of an indexed name must be an array type, -- but it seems that the index types mustn't be used to disambiguate -- the prefix. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package decls is type foo is range 1 to 10; type bar is range 1 to 20; type x is array(foo) of integer; type y is array(bar) of integer; function f(a: integer) return x; function f(a: integer) return y; end package decls; package body decls is function f(a: integer) return x is variable r : x; begin r(1) := a; return r; end; function f(a: integer) return y is variable r : y; begin r(1) := a; return r; end; end decls; entity e is end entity e; use decls.all; architecture a of e is begin p : process variable a : foo; variable b : bar; variable i : integer; variable j : integer; begin j := 1; i := f(j)(a); -- @ERROR@ Ambiguous Types i := f(j)(b); -- @ERROR@ Ambiguous Types end process p; end architecture a; fauhdlc-20130704/tests/error_tests/unconstraint.vhdl0000664000175000017500000000210311137616037022126 0ustar potyrapotyra-- $Id: unconstraint.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- is this valid VHDL? (unconstrained array of unconstrained array) -- doesn't seem to be valid vhdl. lrm doesn't really directly say -- that it's not allowed, but I have found no vhdl compiler so far -- which accepts it. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type byte is array(integer range <>) of bit; type memory is array(integer range <>) of byte; function getsth(m : memory; initializer : bit) return bit; end package t; entity something is end entity something; use t.byte; use t.memory; use t.getsth; architecture implementation of something is begin x : process variable a : byte range 1 to 10; constant c : memory := ("11111111", "111111111"); variable b : bit; begin a := "10011001"; b := getsth(c, 1); end process; end implementation; fauhdlc-20130704/tests/error_tests/proc_wait2.vhdl0000664000175000017500000000162311137616037021456 0ustar potyrapotyra-- $Id: proc_wait2.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- a process with a sensitivity list mustn't contain a wait statement, variant -- via a procedure call. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package procs is procedure dostuff(signal i : in integer); end package procs; package body procs is procedure dostuff(signal i : in integer) is begin wait on i; end; end procs; use procs.dostuff; entity something is end entity something; architecture implementation of something is signal s : integer; begin x : process(s) variable a : integer; begin a := 1; dostuff(s); -- @ERROR@ Wait statement via procedure end process; end implementation; fauhdlc-20130704/tests/error_tests/selnames.vhdl0000664000175000017500000000321311137616037021211 0ustar potyrapotyra-- $Id: selnames.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- test for various different kinds of selected names. -- the last line of this test *must* fail during parsing, because -- selected names are getting looked up there. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package outer2 is signal foo : integer; end package outer2; entity outer1 is signal foo : integer; type R1 is record elem1 : integer; elem2 : integer; end record; type R2 is record elem1 : integer; elem2 : R1; end record; type R3 is record elem1 : R1; elem2 : R2; end record; end entity outer1; architecture inner of outer1 is function foo (foobar : integer) return integer is begin return - foobar; end; begin p1 : process variable foo : integer; variable bar : std.standard.boolean; variable vr1 : r1; variable vr2 : r2; variable vr3 : r3; begin wait on outer1.foo; foo := 2; p1.foo := 3; outer1.foo <= 4; outer2.foo <= 5; work.outer2.foo <= 6; --inner.foo <= 7; -- doesn't make sense. inner.p1.foo := 9; foo := vr1.elem1; foo := vr1.elem2; foo := vr2.elem1; foo := vr2.elem2.elem1; foo := vr2.elem2.elem2; --foo := vr3.elem1; -- error here! foo := vr3.elem1.elem1; foo := vr3.elem1.elem2; foo := vr3.elem2.elem1; foo := vr3.elem2.elem2.elem1; foo := vr3.elem2.elem2.elem2; foo := vr3.outer1; -- @ERROR@ Symbol 'outer1' undefined end process p1; end architecture inner; fauhdlc-20130704/tests/error_tests/port_unused.vhdl0000664000175000017500000000245011137616037021753 0ustar potyrapotyra-- $Id: port_unused.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY forwarder IS PORT ( x_out : OUT integer; x_unused : OUT integer; -- @ERROR@ Unused signal x_in : IN integer ); END ENTITY forwarder; ARCHITECTURE forwarder_impl of forwarder IS BEGIN forward : process (x_in) BEGIN x_out <= x_in; END PROCESS; END ARCHITECTURE forwarder_impl; ENTITY forwarder2 IS PORT ( x_out : OUT integer; x_in : IN integer ); END ENTITY forwarder2; ARCHITECTURE forwarder2_impl of forwarder2 IS BEGIN f : forwarder PORT MAP ( x_in => x_in, x_out => x_out ); END ARCHITECTURE; ENTITY test_bench IS END ENTITY test_bench; ARCHITECTURE test_bench_impl of test_bench IS SIGNAL x, y : integer; BEGIN f : forwarder2 port map (x_in => x, x_out => y); p : process begin x <= 1; wait on y; assert(y = 1) report "y != 1" severity failure; x <= 2; wait on y; assert(y = 2) report "y != 2" severity failure; assert false report "simulation finished." severity note; wait; end process; END ARCHITECTURE; fauhdlc-20130704/tests/error_tests/array_wrong_indices.vhdl0000664000175000017500000000157711137616037023445 0ustar potyrapotyra-- $Id: array_wrong_indices.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- -- assemble an aggregate with a wrong number of indices. -- should yield a type error. -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type small_byte is array(0 to 6) of bit; type large_byte is array(0 to 8) of bit; end package t; entity something is end entity something; use t.small_byte; use t.large_byte; architecture implementation of something is begin x : process variable a : small_byte; variable b : large_byte; begin a := "10011001"; -- @ERROR@ Index out of range b := "10011001"; -- @ERROR@ Indices not covered end process; end implementation; fauhdlc-20130704/tests/error_tests/array_wrong_indices2.vhdl0000664000175000017500000000152711137616037023522 0ustar potyrapotyra-- $Id: array_wrong_indices2.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- -- subscribe to a multimensional array with only one index and vice versa. -- -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type rom128 is array(0 to 128, 0 to 7) of bit; type byte is array(0 to 7) of bit; end package t; entity something is end entity something; use t.rom128; use t.byte; architecture implementation of something is begin x : process variable a : byte; variable b : rom128; begin b(8) := '1'; -- @ERROR@ too few indices a(8, 2) := '0'; -- @ERROR@ too many indices end process; end implementation; fauhdlc-20130704/tests/error_tests/types.vhdl0000664000175000017500000000132011307673414020544 0ustar potyrapotyra-- $Id: types.vhdl 4888 2009-12-09 10:08:12Z potyra $ -- test a for a type error regarding overloads -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library ieee; use ieee.std_logic_1164.all; entity test_bench is end entity test_bench; architecture test_bench_impl of test_bench is signal s: std_logic; begin p : process begin s <= '1' xor '0'; s <= '1' and 0; -- @ERROR@ type error s <= s = '1' and s = 0; -- @ERROR type error end process; end architecture test_bench_impl; fauhdlc-20130704/tests/error_tests/compinst1.vhdl0000664000175000017500000000145411137616037021324 0ustar potyrapotyra-- $Id: compinst1.vhdl 4326 2009-01-27 14:37:19Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY unitA IS GENERIC( g1 : integer := 1; g2 : integer := 2 ); PORT ( p1 : inout integer; p2 : in integer; p3 : out bit ); END ENTITY unitA; ENTITY unitB IS END ENTITY unitB; ARCHITECTURE implementation of unitB is SIGNAL s1 : integer; SIGNAL s2 : integer; SIGNAL s3 : integer; BEGIN instUnit : unitA GENERIC MAP ( g1 => 23, g2 => 42 ) PORT MAP ( p1 => s1, p2 => s2, p3 => s3 -- @ERROR@ type error ); END implementation; fauhdlc-20130704/tests/Makefile.am0000664000175000017500000000734211461270236016210 0ustar potyrapotyra# $Id: Makefile.am 5023 2010-10-25 11:57:18Z potyra $ TESTS = ./run-tests.py EXTRA_DIST=\ run-tests.py\ tests.lists.example\ ./types/tests.list\ ./error_tests/tests.list\ ./icode/tests.list\ ./symboltable/tests.list\ ./types/compinst1.vhdl\ ./types/aggregates.vhdl\ ./types/arrays.vhdl\ ./types/longexp.vhdl\ ./types/phystypes.vhdl\ ./types/selectedoverloads.vhdl\ ./types/conditions.vhdl\ ./types/typedefs.vhdl\ ./error_tests/attr_type.vhdl\ ./error_tests/compinst1.vhdl\ ./error_tests/selnames.vhdl\ ./error_tests/port_visibility.vhdl\ ./error_tests/proc_wait.vhdl\ ./error_tests/for_loop.vhdl\ ./error_tests/test_indices.vhdl\ ./error_tests/unconstraint.vhdl\ ./error_tests/port_unused.vhdl\ ./error_tests/array_wrong_indices.vhdl\ ./error_tests/proc_wait2.vhdl\ ./error_tests/types.vhdl\ ./error_tests/array_wrong_indices2.vhdl\ ./error_tests/while_false.vhdl\ ./icode/double_quotes.vhdl\ ./icode/operators.vhdl\ ./icode/array_param3.vhdl\ ./icode/init1.vhdl\ ./icode/resolved1.vhdl\ ./icode/full_adder.vhdl\ ./icode/wait_on_composite.vhdl\ ./icode/ifstats.vhdl\ ./icode/array_param6.vhdl\ ./icode/generic6.vhdl\ ./icode/arrays_8.vhdl\ ./icode/compinst1.vhdl\ ./icode/generic2.vhdl\ ./icode/assert1.vhdl\ ./icode/port_access.vhdl\ ./icode/generic1.vhdl\ ./icode/resolved2.vhdl\ ./icode/wait.vhdl\ ./icode/sig_assign2.vhdl\ ./icode/array_aggregate2.vhdl\ ./icode/proc2.vhdl\ ./icode/deterministic.vhdl\ ./icode/init2.vhdl\ ./icode/generic5.vhdl\ ./icode/array_ports.vhdl\ ./icode/array_ports4.vhdl\ ./icode/operators2.vhdl\ ./icode/loop.vhdl\ ./icode/array_param1.vhdl\ ./icode/for_loop2.vhdl\ ./icode/attr1.vhdl\ ./icode/array_param4.vhdl\ ./icode/array_ports3.vhdl\ ./icode/arrays_2.vhdl\ ./icode/array_param2.vhdl\ ./icode/condal1.vhdl\ ./icode/array_param5.vhdl\ ./icode/for_loop.vhdl\ ./icode/array_ports2.vhdl\ ./icode/attr2.vhdl\ ./icode/proc_formal2.vhdl\ ./icode/array_aggregate.vhdl\ ./icode/port_unused.vhdl\ ./icode/init3.vhdl\ ./icode/foreign_arch.vhdl\ ./icode/attr4.vhdl\ ./icode/arrays_1.vhdl\ ./icode/arrays_6.vhdl\ ./icode/proc4.vhdl\ ./icode/proc6.vhdl\ ./icode/event.vhdl\ ./icode/while_loop.vhdl\ ./icode/attr3.vhdl\ ./icode/proc1.vhdl\ ./icode/funccalls_1.vhdl\ ./icode/proc_formal3.vhdl\ ./icode/records_1.vhdl\ ./icode/arrays_7.vhdl\ ./icode/generic4.vhdl\ ./icode/for_loop3.vhdl\ ./icode/proc5.vhdl\ ./icode/arrays_5.vhdl\ ./icode/generic3.vhdl\ ./icode/proc_formal1.vhdl\ ./icode/arrays_3.vhdl\ ./icode/proc3.vhdl\ ./icode/sig_assign1.vhdl\ ./icode/case_stat.vhdl\ ./icode/array_param7.vhdl\ ./icode/arrays_4.vhdl\ ./parser_bugs/resolved2.vhdl\ ./parser_bugs/functions.vhdl\ ./symboltable/attributes.vhdl\ ./symboltable/ifstat.vhdl\ ./symboltable/iassoc.vhdl\ ./symboltable/selnames.vhdl\ ./symboltable/arrays.vhdl\ ./symboltable/nested.vhdl\ ./symboltable/funccalls.vhdl\ ./symboltable/useclauses.vhdl\ ./symboltable/phystypes.vhdl\ ./symboltable/std_logic_1164.vhdl\ ./symboltable/functions.vhdl\ ./symboltable/stdlogic.vhdl\ ./symboltable/typedefs.vhdl dist-hook: $(RM) -r $$(find $(distdir) -name .svn) tests: $(top_srcdir)/fauhdlc @./run-tests.py clean-local: find $(builddir) -name "*.std.out" -delete find $(builddir) -name "*.err.out" -delete find $(builddir) -name "*.result" -delete find $(builddir) -name "*.dot" -delete find $(builddir) -name "*.ic" -delete find $(builddir) -name "*.c" -delete # helper rule to generate extra_dist extra_dist.mk: Makefile.am $(RM) $@ echo "EXTRA_DIST=\\" >> $@ echo -e "\trun-tests.py\\" >> $@ echo -e "\ttests.lists.example\\" >> $@ for i in $$(find . -name tests.list); do \ echo -e "\t$$i\\" >> $@; \ done for i in $$(find . -name *.vhdl); do \ echo -e "\t$$i\\" >> $@; \ done .PHONY: tests fauhdlc-20130704/tests/parser_bugs/0000775000175000017500000000000012165333077016467 5ustar potyrapotyrafauhdlc-20130704/tests/parser_bugs/functions.vhdl0000664000175000017500000000273011137616464021362 0ustar potyrapotyra-- $Id: functions.vhdl 4328 2009-01-27 14:41:56Z potyra $ -- test for some different arrays -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library types; use types.standard.all; entity nullentity is end entity nullentity; architecture implementation of nullentity is type R1 is record I: integer; end record; type unconarraytype is array(integer range <>) of r1; type integer_array is array(1 to 10) of integer; function bar(x : integer; y : integer) return integer; -- the following is a homograph of the above (same base type!) function bar(x : integer range 4 to 18; y : integer) return integer; function bar(x : unconarraytype(5 to 16)) return R1; function bar(x : unconarraytype(5 to 16)) return integer_array; function f return r1; function f(x : R1) return R1; function bar(f : integer range 4 to 18) return R1; begin p : process variable v1, v2, v3 : integer; begin v1 := bar(4); v2 := bar(4).i; v3 := bar(x => 4); v1 := bar(y => 4, x => 5); v2 := bar(x => bar(4)); v3 := bar(x, y => bar(bar(4))(5)); -- valid! v1 := f.i; -- call f and do selection to i. v1 := f(x.i => v2); v2 := f(x.i => v2).i; v3 := bar(f(v1) => v3).i; -- f: formal, v1: subscript end process; end implementation; fauhdlc-20130704/tests/parser_bugs/resolved2.vhdl0000664000175000017500000000343211247176045021255 0ustar potyrapotyra-- $Id$ -- test resolution functions -- actually this test doesn't document a parser bug, but rather a -- bug with evaluating resolution functions (which results from a -- not strictly lrm conforming design decision). -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package t is type iv is array(integer range <>) of integer; function resolve_integer_vl(v : iv) return integer; subtype integer_vl is resolve_integer_vl integer; end package t; package body t is function resolve_integer_vl(v : iv) return integer is begin return v'length; end; end; use t.integer_vl; entity d is port ( o : out integer_vl; i1 : in integer; i2 : in integer ); end entity d; architecture d_impl of d is begin update_output : process(i1, i2) begin o <= i1 + i2 after 10 ms; end process; end; entity test_bench is end entity test_bench; use t.integer_vl; architecture test_bench_impl of test_bench is signal r : integer_vl; signal i1 : integer; signal i2 : integer; signal i3 : integer; signal i4 : integer; begin d1 : d port map(o => r, i1 => i1, i2 => i2); d2 : d port map(o => r, i1 => i3, i2 => i4); p : process begin i1 <= 1; i2 <= 2; i3 <= 3; i4 <= 4; wait for 12 ms; -- lrm 2003: there are 2 drivers for the final resolution -- hence the result must be 2. -- fauhdlc doesn't adhere to this. There every -- driver gets connected to the final signal (recursively). -- hence fauhdli's result will be 4. assert r = 2 report "r must be 2" severity failure; assert false report "simulation finished" severity note; wait; end process; end; fauhdlc-20130704/tests/tests.lists.example0000664000175000017500000000202611072407410020014 0ustar potyrapotyra# example file for tests.lists # # everything starting with # is a comment # # The first line contains common options for all test cases in the directory # It can contain the following options: # # DESC="string" # description for group of tests. default: directory name. # COMMON_OPTS="string" # options passed to the compiler for all tests of this group. # default: no additional options # OUTPUT="True" # create intermediate code files. (defaults to False) # DESC="my own test cases", COMMON_OPTS="--funny-option1 --another-option" # # the following lines define test-cases, one per line. # the format is # # description is the description of the test-case # # OPTS defines the compiler options for this specific test case # if not specified, OPTS defaults to no additional options. # QUIET only print brief description of result, don't do verbose # output. Default: "False" # # the main file to execute is description with the suffix .vhdl. description OPTS="--foo --bar" anothertestcase QUIET="True" fauhdlc-20130704/tests/types/0000775000175000017500000000000012165333076015316 5ustar potyrapotyrafauhdlc-20130704/tests/types/selectedoverloads.vhdl0000664000175000017500000000356611137617440021714 0ustar potyrapotyra-- $Id: selectedoverloads.vhdl 4330 2009-01-27 14:50:08Z potyra $ -- test for various different kinds of selected names. -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package outer2 is signal foo : integer; end package outer2; entity outer1 is signal foo : integer; type R1 is record elem1 : integer; elem2 : integer; end record; type R2 is record elem1 : integer; elem2 : R1; end record; type R3 is record elem1 : R1; elem2 : R2; end record; type myArray is array(0 to 1) of r1; end entity outer1; architecture inner of outer1 is function foo (foobar : integer) return integer is begin return - foobar; end; function foo(foobar : R1) return R1 is begin return foobar; end; function foo(foobar : integer) return R1 is variable r : R1; begin r.elem1 := foobar; r.elem2 := foobar; return r; end; function foo(foobar: integer) return R2 is variable r : R2; begin r.elem1 := foobar; r.elem2.elem1 := foobar; r.elem2.elem2 := foobar; return r; end; function foo(foobar: integer) return myarray is variable a : myarray; variable i1 : r1; begin i1.elem1 := foobar; i1.elem2 := foobar; a := (others => i1); return a; end; begin p1 : process variable x : integer; variable rx : R1; variable a : myArray; variable rx3 : R3; begin -- x := foo(3).elem1; -- ambiguous! x := foo(3).elem2; x := foo(rx).elem1; rx := foo(3).elem2; x := foo(3).elem2.elem1; x := a(0).elem1; x := r3.elem2.elem2.elem1; x := a(0 to 1)(0).elem1; x := foo(3)(0).elem1; x := foo(3)(0).elem2; x := foo(42)(0 to 1)(0).elem1; x := foo(42)(0 to 1)(0).elem2; end process p1; end architecture inner; fauhdlc-20130704/tests/types/conditions.vhdl0000664000175000017500000000150111137617440020341 0ustar potyrapotyra-- $Id: conditions.vhdl 4330 2009-01-27 14:50:08Z potyra $ -- mini test for the parser. will use that to test each -- new feature -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY conditions IS END ENTITY; -- -- test architecture declaration ARCHITECTURE cond_imp of conditions IS variable x : integer; variable b : boolean; BEGIN tc : process begin if 1 = 2 then null; end if; if x = 2 then null; end if; -- FIXME type analysis is still wrong. -- if 2 = x then -- null; -- end if; if b then null; end if; end process tc; end ARCHITECTURE cond_imp; fauhdlc-20130704/tests/types/typedefs.vhdl0000664000175000017500000000130211137617440020012 0ustar potyrapotyra-- $Id: typedefs.vhdl 4330 2009-01-27 14:50:08Z potyra $ -- define some basic types in packages std (to be used with initially empty -- symbol table -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. package standard is type BOOLEAN is (FALSE, TRUE); type BIT is ('0', '1'); type INTEGER is range 0 to 2147483647; type NATURAL is range 1 to 10; type SEVERITY_LEVEL is (note, warning, error, failure); type FLOAT is range -1.9e10 to 1.9e10; end package standard; fauhdlc-20130704/tests/types/phystypes.vhdl0000664000175000017500000000226611137617440020251 0ustar potyrapotyra-- $Id: phystypes.vhdl 4330 2009-01-27 14:50:08Z potyra $ -- test for physical types -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library std; use std.standard.all; package types is type length is range -2147483647 to 2147483647 units mm; cm = 10 mm; m = 100 cm; km = 1000 m; inch = 254 mm; end units; type data is range -2147483647 to 2147483647 units bit; nibble = 4 bit; byte = 8 bit; word = 2 byte; kbit = 1000 bit; mbit = 1000 kbit; kb = 1024 byte; mb = 1024 kb; gb = 1024 mb; --meterbit = 10 mm; -- should throw an error. end units; end package types; library std; use std.standard.all; use types.all; entity nullentity is end entity nullentity; architecture implementation of nullentity is begin x : process variable foo : length; variable bar : length; begin foo := 48 mm; bar := 2 * foo + 3 cm; foo := bar - 5 km; bar := foo + 100 inch; end process; end implementation; fauhdlc-20130704/tests/types/longexp.vhdl0000664000175000017500000000352411301021134017631 0ustar potyrapotyra-- $Id: longexp.vhdl 4836 2009-11-18 16:35:40Z potyra $ -- Copyright (C) 2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library ieee; use ieee.std_logic_1164.all; ENTITY tb is END ENTITY tb; ARCHITECTURE impl of tb is signal bus_addr : std_logic_vector(31 downto 0); signal is_own_addr : std_logic; signal is_addr_phase : std_logic; signal conf_addr : std_logic_vector(31 downto 4); BEGIN decode_own_address : process(is_addr_phase) begin if is_addr_phase = '1' and bus_addr(31) = conf_addr(31) and bus_addr(30) = conf_addr(30) and bus_addr(29) = conf_addr(29) and bus_addr(28) = conf_addr(28) and bus_addr(27) = conf_addr(27) and bus_addr(26) = conf_addr(26) and bus_addr(25) = conf_addr(25) and bus_addr(24) = conf_addr(24) and bus_addr(23) = conf_addr(23) and bus_addr(22) = conf_addr(22) and bus_addr(21) = conf_addr(21) and bus_addr(20) = conf_addr(20) and bus_addr(19) = conf_addr(19) and bus_addr(18) = conf_addr(18) and bus_addr(17) = conf_addr(17) and bus_addr(16) = conf_addr(16) and bus_addr(15) = conf_addr(15) and bus_addr(14) = conf_addr(14) and bus_addr(13) = conf_addr(13) and bus_addr(12) = conf_addr(12) and bus_addr(11) = conf_addr(11) and bus_addr(10) = conf_addr(10) and bus_addr(9) = conf_addr(9) and bus_addr(8) = conf_addr(8) and bus_addr(7) = conf_addr(7) and bus_addr(6) = conf_addr(6) and bus_addr(5) = conf_addr(5) and bus_addr(4) = conf_addr(4) then is_own_addr <= '1'; else is_own_addr <= '0'; end if; end process; END ARCHITECTURE impl; fauhdlc-20130704/tests/types/tests.list0000664000175000017500000000043411301021134017332 0ustar potyrapotyra# $Id: tests.list 4836 2009-11-18 16:35:40Z potyra $ DESC="Type resolution" typedefs phystypes arrays # FIXME the following is known bad (due to GenCode) selectedoverloads QUIET="True" aggregates compinst1 conditions longexp OPTS="--lib ieee ../../lib/std_logic_1164.vhdl --lib work" fauhdlc-20130704/tests/types/aggregates.vhdl0000664000175000017500000000231411137617440020304 0ustar potyrapotyra-- $Id: aggregates.vhdl 4330 2009-01-27 14:50:08Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. entity foo is end entity foo; architecture implementation of foo is begin p : process type mystring is array(integer range <>) of character; -- FIXME doesn't work atm, see ResolveTypes (ValDeclaration). --variable x : mystring := "hallo welt"; type byte_a is array(0 to 7) of bit; type word_a is array(0 to 1) of byte_a; variable mem_a : word_a; type word_b is array(0 to 1, 0 to 7) of bit; variable mem_b : word_b; begin mem_a := (0 => "10000001", 1 => "00011000"); mem_a := (0 => (0 => '1', others => '0'), 1 => (3 | 4 => '1', others => '0')); mem_a := (0 => (0 => '1', others => '0'), 1 => (3 to 4 | 5 => '1', others => '0')); mem_b := (0 => (0 => '1', others => '0'), 1 => (3 | 4 => '1', others => '0')); mem_b := (0 => (0 => '1', others => '0'), 1 => (3 to 4 | 5 => '1', others => '0')); end process; end implementation; fauhdlc-20130704/tests/types/arrays.vhdl0000664000175000017500000000267311137617440017504 0ustar potyrapotyra-- $Id: arrays.vhdl 4330 2009-01-27 14:50:08Z potyra $ -- test for some different arrays -- Copyright (C) 2007-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. library std; use std.standard.all; package types is type word is array(0 to 31) of bit; type bitarray is array(INTEGER range <>) of bit; type memory is array(INTEGER range <>) of word; type memory2 is array(0 to 127, 0 to 31) of bit; subtype small is integer range 0 to 127; type memory3 is array(small, 0 to 31) of bit; --type memory3 is array(small1, 0 to 31) of bit; -- illegal: --type memfault is array(INTEGER range <>) of word(0 to 31); end package types; library std; use std.standard.all; use types.all; entity nullentity is end entity nullentity; architecture implementation of nullentity is begin x : process constant memsize : integer := 127; variable foo : word; -- no index constrained allowed here! variable bar : memory(0 to memsize); variable tofu : memory2; -- FIXME see aggregates.vhdl --constant foobar : bitarray := "11110000"; -- (0 to 7) begin bar(0)(0) := '1'; bar(0)(1) := '0'; tofu(0, 0) := '1'; tofu(0, 1) := '0'; bar(0 to 10) := bar(10 to 20); bar(0) := "11110000111100001111000011110000"; end process; end implementation; fauhdlc-20130704/tests/types/compinst1.vhdl0000664000175000017500000000142211137617440020107 0ustar potyrapotyra-- $Id: compinst1.vhdl 4330 2009-01-27 14:50:08Z potyra $ -- Copyright (C) 2008-2009 FAUmachine Team . -- This program is free software. You can redistribute it and/or modify it -- under the terms of the GNU General Public License, either version 2 of -- the License, or (at your option) any later version. See COPYING. ENTITY unitA IS GENERIC( g1 : integer := 1; g2 : integer := 2 ); PORT ( p1 : inout integer; p2 : in integer; p3 : out bit ); END ENTITY unitA; ENTITY unitB IS END ENTITY unitB; ARCHITECTURE implementation of unitB is SIGNAL s1 : integer; SIGNAL s2 : integer; SIGNAL s3 : bit; BEGIN instUnit : unitA GENERIC MAP ( g1 => 23, g2 => 42 ) PORT MAP ( p1 => s1, p2 => s2, p3 => s3 ); END implementation; fauhdlc-20130704/ChangeLog0000664000175000017500000000614012165073733014564 0ustar potyrapotyra2013/07/03 Stefan Potyra : * generic: Fix build failures with gcc-4.8, adapt to changes for new bison version (cf. DBTS: #710626). 2012/06/05 Stefan Potyra : * interpreter: Consistently use memory allocator / deallocator callbacks. 2011/08/12 Stefan Potyra : * backend: Work in progress: Experimental C-backend. Not working yet. * intermediate code: ABI change: move types to separate section. 2010/03/25 Stefan Potyra : * interpreter: Fix build failure on sparc et al. 2010/03/24 Stefan Potyra : * frontend: Fix loop statements without iteration scheme. * frontend: Work around broken nested function calls. * lib: Make std_logic_1164 a tiny little bit more compliant (it's still a long way.) 2009/11/18 Stefan Potyra : * frontend/visitor/ResolveTypes.cpp: Huge speed improvements for long expressions. * interpreter: Complete rewrite of the foreign API to use callbacks. Hopefully further API breakages can be avoided or at least will occur less often. * configure.ac: Link against both gccpp and gc library, Debian BTS: #554277. 2009/09/21 Stefan Potyra : * frontend/visitor/GenCode.cpp: Add support for foreign architectures. An architecture implemented in VHDL and declared as foreign must only instantiate foreign entities, and is only allowed to use foreign ports (which isn't checked yet by the compiler). Then there'll be another set of functions calls to glue_vhdl's foreign interface. * foreign interface: See above, new callbacks and hence (once again) a new API. * Arrays: Support downto arrays. * frontend, interpreter: Support resolution functions. * frontend: Support conditional concurrent signal assignment statements. 2009/05/12 Stefan Potyra : * Generic: Release version 20090512. * frontend/interpreter: store virtual registers in the stack frame. This fixes the problem if procedures with wait statements are called simultaneously from two processes. * frontend: Handle all generic map aspects correctly. * tests: Add more tests for generic maps. * interpreter: Allow multivalue initializers for composites. * frontend: Use multivalue initializers for composites. * interpreter: API of foreign interface for generics splitted to handle arrays and non-arrays differently. 2009/03/09 Stefan Potyra : * build-system: Build the parser generator (bison input file) with different directives based on detected bison versions, as these are not compatible. Debian BTS: #518776. * build-system: Clean up automake hacks. 2009/02/20 Stefan Potyra : * intepreter/kernel.c: Fix cast to not emit warnings on sparc. * frontend/newparser/ParserDriver.[ch]pp: Fix bad return type of getDigitValue. 2009/02/13 Stefan Potyra : * 20090213 released. * General: Ported to Mac OS X (Matthias Sand) 2009/02/02 Stefan Potyra : * frontend/visitor/GenCode.cpp: make waiting on composite signals work fauhdlc-20130704/NEWS0000664000175000017500000000000010547560451013476 0ustar potyrapotyrafauhdlc-20130704/COPYING0000664000175000017500000004310311014552363014036 0ustar potyrapotyra GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. fauhdlc-20130704/acinclude.m40000664000175000017500000000173211622031500015164 0ustar potyrapotyradnl usage: AC_PROG_CXX_OPTION(--compiler-option, if-supported, if-unsupported) dnl add this option to $(CXX) if it is supported by the compiler dnl if no sc dnl Martin Waitz , modified by Stefan Potyra AC_DEFUN([AC_PROG_CXX_OPTION], [ AC_MSG_CHECKING([whether $CXX supports $1]) ac_save_CXX="$CXX" CXX="$CXX $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],[ AC_MSG_RESULT([yes]) ifelse($2, , [], [ CXX="$ac_save_CXX" $2]) ], [ AC_MSG_RESULT([no]) CXX="$ac_save_CXX" $3 ]) ]) dnl usage: AC_PROG_CC_OPTION(--compiler-option, if-supported, if-unsupported) dnl add this option to $(CC) if it is supported by the compiler dnl if no sc dnl Martin Waitz AC_DEFUN([AC_PROG_CC_OPTION], [ AC_MSG_CHECKING([whether $CC supports $1]) ac_save_CC="$CC" CC="$CC $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],[ AC_MSG_RESULT([yes]) ifelse($2, , [], [ CC="$ac_save_CC" $2]) ], [ AC_MSG_RESULT([no]) CC="$ac_save_CC" $3 ]) ]) fauhdlc-20130704/scripts/0000775000175000017500000000000012165333076014477 5ustar potyrapotyrafauhdlc-20130704/scripts/genDVD0000775000175000017500000000063011270006273015523 0ustar potyrapotyra#!/bin/sh date=`date +%Y-%m-%d` dir="fauhdlc-${date}" iso="fauhdlc-${date}.iso" if [ -d ${dir} ] ; then echo "${dir}: exists already" 1>&2 exit 1 fi if [ -f ${iso} ] ; then echo "${iso}: exists already" 1>&2 exit 1 fi mkdir ${dir} cd ${dir} # # copy fauhdlc source repository # cp -a /proj/fauhdlc fauhdlc.repository cd .. # # generate iso image # mkisofs -r -T -v -o ${iso} ${dir} rm -rf ${dir} fauhdlc-20130704/Makefile.am0000664000175000017500000002231211502713055015035 0ustar potyrapotyra# $Id: Makefile.am 5086 2010-12-17 16:56:13Z potyra $ # make sure that frontend/newparser is before ".", so that the generated # parser files will be present already. SUBDIRS=\ frontend/newparser\ .\ interpreter\ lib\ tests \ doc \ misc EXTRA_DIST = autogen.sh noinst_LIBRARIES = libcompiler.a libcompiler_a_SOURCES=\ frontend/ast/NodeFactory.cpp\ frontend/ast/Location.cpp\ frontend/ast/AstNode.cpp\ frontend/ast/AttributableDeclaration.cpp\ frontend/ast/AttributeDeclaration.cpp\ frontend/ast/AttributeSpecification.cpp\ frontend/ast/Name.cpp\ frontend/ast/PhysicalType.cpp\ frontend/ast/SubtypeIndication.cpp\ frontend/ast/RecordType.cpp\ frontend/ast/Types.cpp\ frontend/ast/ConstInteger.cpp\ frontend/ast/DiscreteRange.cpp\ frontend/ast/Expression.cpp\ frontend/ast/SimpleName.cpp\ frontend/ast/SymbolDeclaration.cpp\ frontend/ast/ValDeclaration.cpp\ frontend/misc/Driver.cpp\ frontend/misc/DeclarativeRegion.cpp\ frontend/misc/Symbol.cpp\ frontend/misc/SymbolTable.cpp\ frontend/misc/BuiltinSymbolTable.cpp\ frontend/misc/NameLookup.cpp\ frontend/misc/RegisterBuiltins.cpp\ frontend/misc/RangeSet.cpp\ frontend/reporting/AmbiguousTypes.cpp\ frontend/reporting/CompileError.cpp \ frontend/reporting/DuplicateName.cpp \ frontend/reporting/ErrorRegistry.cpp \ frontend/reporting/TypeError.cpp\ frontend/reporting/TypeMismatch.cpp\ frontend/reporting/UndefinedSymbol.cpp\ frontend/visitor/TopDownVisitor.cpp\ frontend/visitor/DotVisitor.cpp\ frontend/visitor/ResolveAggregates.cpp\ frontend/visitor/ResolveTypes.cpp\ frontend/visitor/ResolveSymbols.cpp\ frontend/visitor/NullVisitor.cpp\ frontend/visitor/GenCode.cpp\ frontend/visitor/GCArrays.cpp\ frontend/visitor/GCTypes.cpp\ frontend/visitor/GCBuiltins.cpp\ frontend/visitor/GCRegisterSet.cpp\ frontend/visitor/SetPathName.cpp\ frontend/visitor/GatherImplicits.cpp\ frontend/visitor/ConstantPropagation.cpp\ frontend/visitor/GCLoops.cpp\ frontend/visitor/CheckLoops.cpp\ frontend/visitor/CheckAccessMode.cpp\ frontend/visitor/NormalizeAssocLists.cpp\ frontend/visitor/SimplifyExpressions.cpp\ frontend/visitor/UnconstraintBounds.cpp\ frontend/visitor/WaitConditions.cpp\ frontend/visitor/WarnUnused.cpp\ frontend/visitor/TransformSigAssign.cpp\ intermediate/container/LabelFactory.cpp\ intermediate/container/TypeFactory.cpp\ intermediate/operands/ImmediateOperand.cpp\ intermediate/operands/RegisterFactory.cpp\ intermediate/visitor/GenCCode.cpp\ intermediate/visitor/LookupSymbols.cpp\ intermediate/visitor/PrintCode.cpp\ intermediate/visitor/StandardTraversal.cpp\ util/mangle_names.c\ \ frontend/ast/Aggregate.hpp\ frontend/ast/Architecture.hpp\ frontend/ast/AssertStat.hpp\ frontend/ast/AssociationElement.hpp\ frontend/ast/AstNode.hpp\ frontend/ast/AttributableDeclaration.hpp\ frontend/ast/AttributeDeclaration.hpp\ frontend/ast/AttributeName.hpp\ frontend/ast/AttributeSpecification.hpp\ frontend/ast/Callable.hpp\ frontend/ast/CaseAlternative.hpp\ frontend/ast/CaseStat.hpp\ frontend/ast/CompInstStat.hpp\ frontend/ast/ConcurrentStat.hpp\ frontend/ast/CondalSigAssign.hpp\ frontend/ast/ConditionedStat.hpp\ frontend/ast/ConstantDeclaration.hpp\ frontend/ast/ConstArray.hpp\ frontend/ast/ConstInteger.hpp\ frontend/ast/ConstReal.hpp\ frontend/ast/DiscreteRange.hpp\ frontend/ast/ElementAssociation.hpp\ frontend/ast/Entity.hpp\ frontend/ast/EnumerationElement.hpp\ frontend/ast/EnumerationType.hpp\ frontend/ast/ExitStat.hpp\ frontend/ast/Expression.hpp\ frontend/ast/ForLoopStat.hpp\ frontend/ast/FunctionCall.hpp\ frontend/ast/FunctionDeclaration.hpp\ frontend/ast/IfStat.hpp\ frontend/ast/Library.hpp\ frontend/ast/LibraryList.hpp\ frontend/ast/LibUnit.hpp\ frontend/ast/Location.hpp\ frontend/ast/LoopStat.hpp\ frontend/ast/Name.hpp\ frontend/ast/NextStat.hpp\ frontend/ast/NodeFactory.hpp\ frontend/ast/NullStat.hpp\ frontend/ast/Others.hpp\ frontend/ast/PackageBody.hpp\ frontend/ast/Package.hpp\ frontend/ast/PhysicalType.hpp\ frontend/ast/PhysicalTypeUnit.hpp\ frontend/ast/PrefixedName.hpp\ frontend/ast/ProcCallStat.hpp\ frontend/ast/ProcedureDeclaration.hpp\ frontend/ast/Process.hpp\ frontend/ast/RangeConstraintType.hpp\ frontend/ast/RecordTypeElement.hpp\ frontend/ast/RecordType.hpp\ frontend/ast/ReturnStat.hpp\ frontend/ast/SelectedName.hpp\ frontend/ast/SeqStat.hpp\ frontend/ast/SigAssignStat.hpp\ frontend/ast/SignalDeclaration.hpp\ frontend/ast/SimpleName.hpp\ frontend/ast/Slice.hpp\ frontend/ast/SubprogBody.hpp\ frontend/ast/Subscript.hpp\ frontend/ast/SubtypeIndication.hpp\ frontend/ast/SymbolDeclaration.hpp\ frontend/ast/TemporaryName.hpp\ frontend/ast/TypeConversion.hpp\ frontend/ast/TypeDeclaration.hpp\ frontend/ast/Types.hpp\ frontend/ast/UnconstrainedArrayType.hpp\ frontend/ast/ValDeclaration.hpp\ frontend/ast/VarAssignStat.hpp\ frontend/ast/VarDeclaration.hpp\ frontend/ast/WaitStat.hpp\ frontend/ast/WaveFormElem.hpp\ frontend/ast/WhileLoopStat.hpp\ frontend/misc/BuiltinFunction.hpp\ frontend/misc/BuiltinSymbolTable.hpp\ frontend/misc/DeclarativeRegion.hpp\ frontend/misc/Driver.hpp\ frontend/misc/NameLookup.hpp\ frontend/misc/RangeSet.hpp\ frontend/misc/RegisterBuiltins.hpp\ frontend/misc/StackTrace.hpp\ frontend/misc/Symbol.hpp\ frontend/misc/SymbolTable.hpp\ frontend/newparser/ParserDriver.hpp\ frontend/reporting/AmbiguousTypes.hpp\ frontend/reporting/CompileError.hpp\ frontend/reporting/DuplicateName.hpp\ frontend/reporting/ErrorRegistry.hpp\ frontend/reporting/SyntaxError.hpp\ frontend/reporting/TypeError.hpp\ frontend/reporting/TypeMismatch.hpp\ frontend/reporting/UndefinedSymbol.hpp\ frontend/visitor/CheckAccessMode.hpp\ frontend/visitor/CheckLoops.hpp\ frontend/visitor/ConstantPropagation.hpp\ frontend/visitor/DotVisitor.hpp\ frontend/visitor/GatherImplicits.hpp\ frontend/visitor/GCArrays.hpp\ frontend/visitor/GCBuiltins.hpp\ frontend/visitor/GCLoops.hpp\ frontend/visitor/GCRegisterSet.hpp\ frontend/visitor/GCTypes.hpp\ frontend/visitor/GenCode.hpp\ frontend/visitor/LookupTypes.hpp\ frontend/visitor/NormalizeAssocLists.hpp\ frontend/visitor/NullVisitor.hpp\ frontend/visitor/ResolveAggregates.hpp\ frontend/visitor/ResolveSymbols.hpp\ frontend/visitor/ResolveTypes.hpp\ frontend/visitor/SetPathName.hpp\ frontend/visitor/TopDownVisitor.hpp\ frontend/visitor/Visitor.hpp\ frontend/visitor/WaitConditions.hpp\ frontend/visitor/WarnUnused.hpp\ intermediate/container/CodeContainer.hpp\ intermediate/container/Data.hpp\ intermediate/container/LabelFactory.hpp\ intermediate/container/Label.hpp\ intermediate/container/TypeElement.hpp\ intermediate/container/TypeFactory.hpp\ intermediate/container/Type.hpp\ intermediate/Node.hpp\ intermediate/opcodes/Abort.hpp\ intermediate/opcodes/Add.hpp\ intermediate/opcodes/AOffset.hpp\ intermediate/opcodes/BeginTransfer.hpp\ intermediate/opcodes/Call.hpp\ intermediate/opcodes/Connect.hpp\ intermediate/opcodes/Div.hpp\ intermediate/opcodes/EndTransfer.hpp\ intermediate/opcodes/GetParam.hpp\ intermediate/opcodes/GetSig.hpp\ intermediate/opcodes/IMul.hpp\ intermediate/opcodes/Jbe.hpp\ intermediate/opcodes/Jb.hpp\ intermediate/opcodes/Je.hpp\ intermediate/opcodes/Jmp.hpp\ intermediate/opcodes/Jne.hpp\ intermediate/opcodes/Log.hpp\ intermediate/opcodes/Mov.hpp\ intermediate/opcodes/OpCode.hpp\ intermediate/opcodes/Proc.hpp\ intermediate/opcodes/Return.hpp\ intermediate/opcodes/ROffset.hpp\ intermediate/opcodes/SetParam.hpp\ intermediate/opcodes/Sub.hpp\ intermediate/opcodes/Suspend.hpp\ intermediate/opcodes/Update.hpp\ intermediate/opcodes/WakeAt.hpp\ intermediate/opcodes/WakeOn.hpp\ intermediate/operands/ImmediateOperand.hpp\ intermediate/operands/IndirectOperand.hpp\ intermediate/operands/Operand.hpp\ intermediate/operands/Reference.hpp\ intermediate/operands/RegisterFactory.hpp\ intermediate/operands/Register.hpp\ intermediate/visitor/PrintCode.hpp\ intermediate/visitor/Visitor.hpp\ \ util/GarbageCollect.hpp\ util/MiscUtil.hpp\ util/basetypes.h\ util/mangle_names.h\ \ frontend/ast/NodeFactory.tpp\ frontend/newparser/ParserDriver.tpp\ frontend/visitor/DotVisitor.tpp\ frontend/visitor/Visitor.tpp\ util/MiscUtil.tpp bin_PROGRAMS = fauhdlc fauhdlc_SOURCES=\ compiler/FAUhdlc.cpp\ \ compiler/FAUhdlc.hpp fauhdlc_LDADD=\ frontend/newparser/libnewparser.a \ libcompiler.a \ @GCCPPLDFLAGS@ fauhdlc_CXXFLAGS=-Wno-parentheses fauhdlc_CPPFLAGS=-DVHDL_DATA_DIR=\"$(pkgdatadir)\" # clean up everything mrproper: clean distclean find . -name Makefile.in | xargs rm $(RM) -r autom4te.cache/ $(RM) scripts/depcomp $(RM) scripts/install-sh $(RM) scripts/missing $(RM) scripts/ylwrap $(RM) aclocal.m4 $(RM) configure $(RM) -r doc/interpreter_doxygen/ $(RM) -r doc/compiler_doxygen/ $(RM) INSTALL doc: doc/compiler_doxygen.cf doc/interpreter_doxygen.cf doxygen doc/compiler_doxygen.cf doxygen doc/interpreter_doxygen.cf tests: all $(MAKE) -C tests/ $(AM_MAKEFLAGS) $@ devel: $(CURDIR)/$(top_srcdir)/misc/install_ln.sh $(MAKE) install INSTALL=$< # run cppcheck cppcheck: $(CPPCHECK) -j 4 -q -I $(top_srcdir) \ -I $(top_srcdir)/util \ -I $(top_srcdir)/interpreter \ -I $(top_srcdir)/interpreter/util \ -I $(top_srcdir)/interpreter/glue \ --inline-suppr \ --enable=style $(top_srcdir) .PHONY: mrproper doc devel tests cppcheck fauhdlc-20130704/configure.ac0000664000175000017500000000553112165333100015266 0ustar potyrapotyra# $Id: configure.ac 5078 2010-12-17 14:25:10Z potyra $ AC_INIT(fauhdlc, 20130704) # don't spam / AC_CONFIG_AUX_DIR(scripts) AM_INIT_AUTOMAKE AC_PROG_CC # need c++ AC_PROG_CXX AC_LANG(C++) # need (f)lex AM_PROG_LEX AC_PROG_YACC # need ranlib AC_PROG_RANLIB AC_PROG_LN_S AC_PROG_CC_OPTION(-Wchar-subscripts) AC_PROG_CC_OPTION(-Wcomment) AC_PROG_CC_OPTION(-Wformat) AC_PROG_CC_OPTION(-Wnonnull) AC_PROG_CC_OPTION(-Wimplicit-int) AC_PROG_CC_OPTION(-Wimplicit-function-declaration) AC_PROG_CC_OPTION(-Wimplicit) AC_PROG_CC_OPTION(-Wmain) AC_PROG_CC_OPTION(-Wmissing-braces) AC_PROG_CC_OPTION(-Wparentheses) AC_PROG_CC_OPTION(-Wsequence-point) AC_PROG_CC_OPTION(-Wreturn-type) AC_PROG_CC_OPTION(-Wswitch) AC_PROG_CC_OPTION(-Wtrigraphs) AC_PROG_CC_OPTION(-Wunused-function) AC_PROG_CC_OPTION(-Wunused-label) AC_PROG_CC_OPTION(-Wunused-variable) AC_PROG_CC_OPTION(-Wunused-value) AC_PROG_CC_OPTION(-Wuninitialized) AC_PROG_CC_OPTION(-Wunknown-pragmas) AC_PROG_CC_OPTION(-Wstrict-aliasing) AC_PROG_CC_OPTION(-Winline) AC_PROG_CC_OPTION(-Wendif-labels) AC_PROG_CC_OPTION(-Wshadow) AC_PROG_CC_OPTION(-Wpointer-arith) AC_PROG_CC_OPTION(-Wcast-qual) AC_PROG_CC_OPTION(-Wcast-align) AC_PROG_CC_OPTION(-Wwrite-strings) AC_PROG_CC_OPTION(-Waggregate-return) AC_PROG_CC_OPTION(-Wstrict-prototypes) AC_PROG_CC_OPTION(-Wnested-externs) # FIXME doesn't exist #AC_PROG_CC_OPTION(-Wno-unused-result) AC_PROG_CC_OPTION(-fPIC) AC_PROG_CC_OPTION(-fvisibility=hidden) AC_PROG_CC_OPTION(-U_FORTIFY_SOURCE) # enable g++ checks (will be part of $CXX) AC_PROG_CXX_OPTION(-Wall) AC_PROG_CXX_OPTION(-Wextra) AC_PROG_CXX_OPTION(-Wendif-labels) AC_PROG_CXX_OPTION(-Wshadow) AC_PROG_CXX_OPTION(-Wpointer-arith) AC_PROG_CXX_OPTION(-Wcast-qual) AC_PROG_CXX_OPTION(-Wcast-align) AC_PROG_CXX_OPTION(-Wwrite-strings) AC_PROG_CXX_OPTION(-Wstrict-aliasing) AC_PROG_CXX_OPTION(-Wsign-compare) AC_PROG_CXX_OPTION(-Wconversion) AC_PROG_CXX_OPTION(-Wwrite-strings) AC_PROG_CXX_OPTION(-Wno-unused-parameter) AC_PROG_CXX_OPTION(-Wold-style-cast) AC_PROG_CXX_OPTION(-U_FORTIFY_SOURCE) AC_ARG_ENABLE(Werror, AS_HELP_STRING([--disable-Werror],[disable build with Werror]), [], [disable_Werror=no]) if test "$disable_Werror" = "no"; then AC_PROG_CXX_OPTION(-Werror) AC_PROG_CC_OPTION(-Werror) fi # for . Doesn't work on osx yet :/ #AC_PROG_CXX_OPTION(-std=c++0x) AC_CHECK_HEADERS(gc/gc_cpp.h, [GCCPPLDFLAGS="-lgccpp -lgc"], [AC_MSG_WARN([Please use libgc])]) AC_CHECK_LIB([gc], [GC_malloc], [true], [AC_MSG_WARN([Please use libgc])]) AC_SUBST([GCCPPLDFLAGS]) AC_CHECK_PROGS(XMLTO, xmlto) if test -z "$XMLTO"; then AC_MSG_ERROR([xmlto not found.]) fi AC_CHECK_PROGS(CPPCHECK, cppcheck, false --) # we want these Makefiles AC_CONFIG_FILES([\ Makefile frontend/newparser/Makefile tests/Makefile interpreter/Makefile lib/Makefile doc/Makefile doc/man/Makefile misc/Makefile ]) # finally create the Makefiles AC_OUTPUT() fauhdlc-20130704/autogen.sh0000775000175000017500000000110311245517554015007 0ustar potyrapotyra#!/bin/sh # $Id: autogen.sh 4616 2009-08-27 14:59:56Z potyra $ # # convenience script to setup autotools. # # Copyright (C) 2007-2009 FAUmachine Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. set -e # create scripts directory in case it doesn't exist yet if [ ! -d scripts ]; then mkdir -p scripts fi autoreconf -i echo echo "Now run ./configure to proceed in building FAUhdlc." fauhdlc-20130704/doc/0000775000175000017500000000000012165333077013556 5ustar potyrapotyrafauhdlc-20130704/doc/compiler_doxygen.cf0000664000175000017500000015154611110306232017431 0ustar potyrapotyra# $Id: compiler_doxygen.cf 3853 2008-11-17 15:24:10Z potyra $ # Doxyfile 1.5.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = fauhdlc # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc/compiler_doxygen/ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = YES # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = frontend intermediate util # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.cpp *.c *.hpp *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO fauhdlc-20130704/doc/intermediate_code.txt0000664000175000017500000001501411457050267017764 0ustar potyrapotyra=========================================== = FAUHdlc - intermediate code description = =========================================== Code containers --------------- Code containers are the basic containers in which all intermediate code resides. A code container can be seen as a function container, defining one function. Inside a code container, an arbitrary number of code containers can be nested. A code container can have four segments, all of which are optional: * type definitions segment: Types, e.g. arrays and records are stored here. These ar valid in the entire code container and subcontainers. * transfer segment: The transfer segment defines function call parameters, that can be passed into the code container (or out of it as well, e.g. for OUT parameters). * stack segment: The stack segment defines local variables of the code container. * text segment: The text segment contains the function definition, i.e. a number of opcodes defining the behaviour of the container. The text segment must either end with a return opcode, or must be implemented as an infinite loop. Visibility ---------- In a code container, the definitions of each surrounding code container are visible. This means that types and data from surrounding code container can be accessed in the text segment, and call statements may call surrounding code containers. Furthermore, the direct child containers are visible for calls as well, hence allowing to call one layer downwards. Data/transfer segments of nested containers are however not visible to the surrounding container. As an exception, the transfer segment may be made visible via BEGINTRANS, ENDTRANS and SETPARAM opcodes, in order to pass parameters to function calls. Labels found in text segment are only visible within this text segment, as jump/branch statements must not cross the boundary of one text segment. Basic simulation structure -------------------------- The basic simulation structure should define one top container, which doesn't have a transfer segment (i.e. no parameters) and the text segment of this top container should initialize the simulation by creating signals, connecting drivers and creating processes. Usually, sub-containers holding initialization functionality for sub-components will be called in this phase in order to create a hierarchy. The call to the top container's text segment must always return, and may not be an infinite loop. This allows that process handling needn't be present during this initialization phase. As an additional restriction, no process affecting statements (SUSPEND, WAKEON, WAKEAT) may be present in this phase. The entity that should get simulated, must be a direct child of the top container, and must not need any parameters from outside, i.e. it must not have a transfer segment. Opcodes ------- The definition of opcodes can be found in intermediate/opcodes/*, where the behaviour of the opcodes is described as well. An example implementation is interpreter/*. In case of doubt, the example implementation denotes the desired effect. Operands -------- All operands denote values of at least 64 bit, or at least the size of a pointer on the desired platform, whichever is more. Specifications of all operands can be found in intermediate/operands. Operands in the form of References to code containers (SETPARAM, CALL, etc.), labels and type elements must be resolved according to the visibility rules above. It is an error, if any ambiguity arises from resolution, or if the resolution fails. The types universal_int, and universal_real must be predefined to denote basic signed integer/basic floating point types. Other names may be predefined as well, as long as this will not result in ambiguity. (TODO: simulation_abort?) Annotations ----------- Annotations are basically comments, and can be placed at any place where whitespace is allowed in the intermediate code. An annotation starts with a "{" character, and ends at the next closing curly bracket "}" (unless it is specified in a specification string, see below). Annotations in the form of name="string" or name=123 (cf. scanner of example implementation for lexical definition) denotes a annotation specification, that can have an implementation dependant effect. An implementation may restrict annotation specifications to be present only at limited places inside the intermediate code. =================== = Foreign signals = =================== The treatment of foreign signals is implementation spefic. However, since I constantly forget the reason why fauhdli does it that way, here are some notes how it is done: For a foreign signal that is being read by VHDL, a driver is created which will get connected via glue_vhdl. For a foreign signal that is written to from VHDL, a foreign driver is created. The value of this driver is only passed later on via glue-vhdl, after all non-foreign signals have been handled. The reason is the following: Propagating the value via a glue-vhdl means to basically execute a foreign process. This must happen at a discrete step in the simulation cycle to guarantuee correctness: First, all drivers update signal values. Next, all processes run, where the previously changed signals can result in driver updates. In the same discrete point in time, a signal update may never result in a signal update, and a driver update may never result in a driver update. Resolution functions: It's not possible to use VHDL resolution functions for foreign signals, as the aforementioned semantics imply that actually resolution is performed by the foreign signal (Consider a foreign signal that is read from and written to in VHDL, it has one or more foreign drivers, which forwards VHDL changes to glue_vhdl and one hidden driver, which actually represents the signal value). If resolution was possible by taking all drivers, resolve them to the signal value and forward the result, then a lock to a dominant value could occur: As an example, both the foreign signal and the VHDL counterpart have all driving values set to 'Z', so all signal values are also 'Z'. If now VHDL sets one driver to '0', this one will be dominant. It's passed on to the foreign signal which will also set it's value to '0', like the VHDL value. As a result the hidden foreign input driver for the VHDL signal will have the driving value '0'. Setting the driver back to 'Z' which caused the transition to '0' will still locally resolve to '0', due to the other "segment" of the bus having been forced to '0'. And that's why it all comes down to using only the foreign side for resolutions. fauhdlc-20130704/doc/man/0000775000175000017500000000000012165333077014331 5ustar potyrapotyrafauhdlc-20130704/doc/man/fauhdli.1.xml0000664000175000017500000001025411306221251016612 0ustar potyrapotyra ]>
<info@faumachine.org>
FAUmachine Team 2009 FAUmachine Team Developed at Friedrich Alexander University Erlangen-Nuremberg. FAUhdlc comes with ABSOLUTELY NO WARRANTY. FAUhdlc is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See COPYING for details.
FAUHDLI 1 &binary; Interprete intermediate code that was generated from fauhdlc. &binary; DESCRIPTION &binary; is an interpreter for the intermediate code files that result from the VHDL compiler fauhdlc. OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. , Enable debugging, which will print out line numbers for each intermediate code line that is processed. , top-entity Use top-entity as start of the simulation, e.g."work:test_bench". , vcd-file Output the signal changes into vcd-file. The result can be viewed with gtkwave. , entity Trace all signals in entity. Use in conjunction with . May be specified more than once. SEE ALSO fauhdlc 1 CONTACT Please report all bugs to FAUmachine Team info@faumachine.org. FAUmachine/fauhdlc Homepage .
fauhdlc-20130704/doc/man/Makefile.am0000664000175000017500000000047411133421106016353 0ustar potyrapotyra# $Id: Makefile.am 4286 2009-01-14 17:35:02Z potyra $ # # Copyright (C) 2009 FAUmachine Team . # This program is free software, GPL-2 (or any later version). See COPYING. CLEANFILES = $(man_MANS) EXTRA_DIST = fauhdlc.1 fauhdli.1 man_MANS = fauhdlc.1 fauhdli.1 %.1: %.1.xml $(XMLTO) man $< fauhdlc-20130704/doc/man/fauhdlc.1.xml0000664000175000017500000001375611460274661016634 0ustar potyrapotyra ]>
<info@faumachine.org>
FAUmachine Team 2009-2010 FAUmachine Team. Developed at Friedrich Alexander University Erlangen-Nuremberg. FAUhdlc comes with ABSOLUTELY NO WARRANTY. FAUhdlc is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See COPYING for details.
FAUHDLC 1 &binary; Compile VHDL files to intermediate code. &binary; DESCRIPTION &binary; is a VHDL compiler, that will output intermediate code or C-code. It supports a subset of the VHDL 2000 standard. OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. , Show summary of options. , output-file Output intermediate code into output-file. , library-name Put the following VHDL-files into the library with name library-name. If no is present, all files will be put into the library "work". , Do not preload any library except std.vhdl. By default, &binary; will preload common libraries (currently only std_logic_1164) in the appropriate library namespace. The prevents this behaviour, for example if you want to override the implementation of such a library. Treat warnings as errors. , Stop with compilation after parsing the source file(s). Mainly useful for debugging the compiler. , dot-file Output the raw syntax tree into dot-file, which can be used with the GraphViz tools. , dot-file Output the syntax tree that exists after performing constant folding into dot-file, which can be used with the GraphViz tools. , c-file Generate output as a C file c-file, that can be compiled with a C-compiler, e.g. gcc. This option is yet experimental. SEE ALSO fauhdli 1 CONTACT Please report all bugs to FAUmachine Team info@faumachine.org. FAUmachine/fauhdlc Homepage .
fauhdlc-20130704/doc/interpreter_doxygen.cf0000664000175000017500000015152011110307354020160 0ustar potyrapotyra# $Id: interpreter_doxygen.cf 3854 2008-11-17 15:34:04Z potyra $ # Doxyfile 1.5.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = fauhdli # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc/interpreter_doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = interpreter util # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.c *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO fauhdlc-20130704/doc/Makefile.am0000664000175000017500000000045111133375627015613 0ustar potyrapotyra# $Id: Makefile.am 4277 2009-01-14 14:49:59Z potyra $ # # Copyright (C) 2009 FAUmachine Team . # This program is free software, GPL-2 (or any later version). See COPYING. SUBDIRS = man EXTRA_DIST = \ intermediate_code.txt \ interpreter_doxygen.cf \ compiler_doxygen.cf fauhdlc-20130704/README0000664000175000017500000000410111532706535013665 0ustar potyrapotyra -- -- -- -- ---- VVVVVV VVVV V V @@| @@| @@@|-- @@| @@@@/ VVVVV VVV VV VV VV @@| @@| @@|@@|- @@| @@/ VV VV VV VV VV @@| @@| @@| @@| @@| @@| VVVV VVVVVVVV VV VV @@@@@@@| @@| @@ @@| @@| VV VV VV VV VV @@| @@| @@|@@ @@|----- @@|--- V V V VVVVVV @@/ @@/ @@@@ @@@@@@@/ @@@@/ ============================== = FAUhdlc - a VHDL compiler. = ============================== Copyright (C) 2007-2011 by FAUmachine team , Copyright (C) 2007-2011 Department of Computer Science 3, Friedrich Alexander University Erlangen-Nuremberg, Germany FAUhdlc is part of the FAUmachine project, see . License: GPL. See COPYING for details. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Compiling: To build the package you need the following software: * C/C++-Compiler * bison, at least version 2.1a * flex * automake/autoconf * libgc (the garbage collect library). *********************************** additional make rules apart from standard ones: mrproper: Make the project fresh and shiny again, and delete any generated bit. tests/tests: run the test-suite (python needed for this) doc: Generate doxygen documenation in doc/. The doxygen and dot program is needed for this. fauhdlc-20130704/frontend/0000775000175000017500000000000012165333076014627 5ustar potyrapotyrafauhdlc-20130704/frontend/misc/0000775000175000017500000000000012165333076015562 5ustar potyrapotyrafauhdlc-20130704/frontend/misc/Symbol.cpp0000664000175000017500000001076711243502417017537 0ustar potyrapotyra/* $Id: Symbol.cpp 4556 2009-08-21 11:29:19Z potyra $ * * Symbol: A symbol refers to a named entity. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/misc/Symbol.hpp" #include "frontend/misc/DeclarativeRegion.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/visitor/ResolveTypes.hpp" namespace ast { /* * same name and: * <= 1 is overloadable -> true * 2 is overloadable and * same parameter/result type profile -> true * falltrhough: false */ bool Symbol::isHomograph(const Symbol& other) const { if (*(this->name) != *(other.name)) { return false; } unsigned int overloadable = SYMBOL_FUNCTION | SYMBOL_PROCEDURE; if ((this->type | other.type | overloadable) != overloadable) { //at most one is overloadable //i.o.w: at least on is not overloadable return true; } //both are overloadable //are both procedures? if ((this->type | other.type) == SYMBOL_PROCEDURE) { return this->sameParameterProfile(other); } //is only one a procedure? if (((this->type | other.type) & SYMBOL_PROCEDURE) != 0) { // cannot match on result type profile -> not homographic return false; } //are both functions? if ((this->type | other.type) == SYMBOL_FUNCTION) { bool ret = this->sameResultProfile(other); ret = ret && this->sameParameterProfile(other); return ret; } // not overloadable: -> homographs. return false; } bool Symbol::sameParameterProfile(const Symbol& other) const { Callable* c1 = dynamic_cast(&this->declaration); Callable* c2 = dynamic_cast(&other.declaration); assert(c1); assert(c2); if (c1->arguments == NULL) { return c2->arguments == NULL; } if (c2->arguments == NULL) { return false; } if (c1->arguments->size() != c2->arguments->size()) { return false; } std::list::const_iterator i = c1->arguments->begin(); std::list::const_iterator j = c2->arguments->begin(); // check base type of subtype of both while ((i != c1->arguments->end()) && (j != c2->arguments->end())) { assert((*i)->subtypeIndic); assert((*j)->subtypeIndic); if (! this->baseTypeEqual( *(*i)->subtypeIndic, *(*j)->subtypeIndic)) { return false; } i++; j++; } // same number of parameters? return true; } bool Symbol::sameResultProfile(const Symbol& other) const { FunctionDeclaration *f1 = dynamic_cast(&this->declaration); FunctionDeclaration *f2 = dynamic_cast(&other.declaration); assert(f1); assert(f2); // there must have been a compile error, otherwise the // returnType s must have been set. if (f1->returnType == NULL) { return false; } if (f2->returnType == NULL) { return false; } return this->baseTypeEqual(*(f1->returnType), *(f2->returnType)); } bool Symbol::baseTypeEqual( const SubtypeIndication& s1, const SubtypeIndication& s2 ) { // must have thrown an error during resolving. if (s1.declaration == NULL) { return false; } // must have thrown an error during resolving. if (s2.declaration == NULL) { return false; } return ResolveTypes::baseTypeEqual(*s1.declaration, *s2.declaration); } void Symbol::put(std::ostream& stream) const { stream << *name << ": "; switch(this->type) { case SYMBOL_ENTITY: stream << "Entity"; break; case SYMBOL_PROCEDURE: stream << "Procedure"; break; case SYMBOL_FUNCTION: stream << "Function"; break; case SYMBOL_SIGNAL: stream << "Signal"; break; case SYMBOL_VARIABLE: stream << "Variable/Constant"; break; case SYMBOL_TYPE: stream << "Type"; break; case SYMBOL_UNIT: stream << "Physical Unit"; break; case SYMBOL_ELEMENT: stream << "Record element"; break; case SYMBOL_ATTRIBUTE: stream << "Attribute"; break; case SYMBOL_ARCHITECTURE: stream << "Architecture"; break; case SYMBOL_PROCESS: stream << "Process"; break; case SYMBOL_LOOP: stream << "Loop"; break; case SYMBOL_LIBRARY: stream << "Library"; break; case SYMBOL_PACKAGE: stream << "Package"; break; case SYMBOL_ALL: stream << "ALL token"; break; case SYMBOL_PARAMETER: stream << "Parameter"; break; case SYMBOL_PORT: stream << "Port"; break; } } std::ostream& operator<<(std::ostream& stream, const Symbol& sym) { sym.put(stream); return stream; } }; /* namespace ast */ fauhdlc-20130704/frontend/misc/Driver.cpp0000664000175000017500000000122411137610234017510 0ustar potyrapotyra/* $Id: Driver.cpp 4323 2009-01-27 13:48:12Z potyra $ * Driver: one driver associated to a signal name. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/misc/Driver.hpp" #include "frontend/ast/SimpleName.hpp" namespace ast { Driver::Driver( const SignalDeclaration &d, unsigned int counter, SimpleName *reference ) : signal(d), n(reference), cnt(counter) {} Driver::~Driver() {} }; fauhdlc-20130704/frontend/misc/SymbolTable.cpp0000664000175000017500000001662711137610234020507 0ustar potyrapotyra/* $Id: SymbolTable.cpp 4323 2009-01-27 13:48:12Z potyra $ * * SymbolTable: Raw storage facility for symbols. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include "frontend/misc/SymbolTable.hpp" #include "frontend/misc/RegisterBuiltins.hpp" #define DEBUG 0 namespace ast { SymbolTable::SymbolTable() { } SymbolTable::~SymbolTable() { for (std::list::const_iterator i = this->libraries.begin(); i != this->libraries.end(); i++) { DeclarativeRegion* r = (*i)->region; assert(r); delete r; delete *i; } } Symbol* SymbolTable::registerSymbol( enum symType type, SymbolDeclaration &decl ) { assert(! this->regionStack.empty()); DeclarativeRegion* current = this->getCurrentRegion(); Symbol* sym = new Symbol(decl.name, type, NULL, decl); // FIXME potyra use s.th. different current->registerSymbol(sym); /* register builtin operations for type symbols as well. */ if (type == SYMBOL_TYPE) { RegisterBuiltins::regTypeOps(decl, *this); } #if DEBUG std::cerr << __func__ << ": register=" << *sym << std::endl; #endif return sym; } void SymbolTable::registerSymbolWithRegion( enum symType type, ast::SymbolDeclaration &decl) { DeclarativeRegion *current; DeclarativeRegion *region; current = this->getCurrentRegion(); assert(current); this->pushNewRegion(); region = this->getCurrentRegion(); assert(region); Symbol *sym = new Symbol(decl.name, type, region, decl); current->registerSymbol(sym); decl.region = region; assert(type != SYMBOL_TYPE); /* shouldn't happen, need to Register builtins here. */ #if DEBUG std::cerr << __func__ << ": register=" << *sym << std::endl; #endif } void SymbolTable::pushNewRegion(void) { assert(! this->regionStack.empty()); DeclarativeRegion* current = this->regionStack.top(); assert(current); DeclarativeRegion* n = new DeclarativeRegion(current); this->regionStack.push(n); } void SymbolTable::pushLibrary(Library &node) { // there shouldn't be a parent region on the stack. assert(this->regionStack.empty()); DeclarativeRegion *n = NULL; // check for existing libraries with same name. for (std::list::const_iterator i = this->libraries.begin(); i != this->libraries.end(); i++) { if ((*(*i)->name) == (*node.name)) { n = (*i)->region; break; } } // eventually allocate new region. if (n == NULL) { n = new DeclarativeRegion(NULL); Symbol *sym = new Symbol(node.name, SYMBOL_LIBRARY, n, node); // push on library list this->libraries.push_back(sym); // add it to imported symbols (as it must be rendered invisible, in // case a Homograph hides it in the library region, instead of // creating a duplicate name error). n->imports.push_back(sym); // set the region of the symbol to the current region node.region = n; } // push new region on stack this->regionStack.push(n); } void SymbolTable::pushRegion(DeclarativeRegion ®ion) { assert(! this->regionStack.empty()); this->regionStack.push(®ion); } void SymbolTable::popRegion(void) { assert(! this->regionStack.empty()); this->regionStack.pop(); } std::list SymbolTable::lookup(const std::string &name) const { DeclarativeRegion *current = this->getCurrentRegion(); assert(current); std::list ret = current->lookup(name); #if DEBUG std::cerr << __func__ << " for " << name << std::endl; for (std::list::const_iterator i = ret.begin(); i != ret.end(); i++) { std::cerr << " " << **i << std::endl; } std::cerr << "----" << std::endl; #endif return ret; } void SymbolTable::importSymbol(Symbol &sym) { DeclarativeRegion* current = this->getCurrentRegion(); assert(current); for (std::list::const_iterator i = current->imports.begin(); i != current->imports.end(); i++) { if (*i == &sym) { return; } } current->imports.push_back(&sym); #if DEBUG std::cerr << __func__ << ": importing=" << sym << std::endl; #endif } bool SymbolTable::addlibrary(const std::string &name) { for (std::list::const_iterator i = this->libraries.begin(); i != this->libraries.end(); i++) { if ((*i)->name && (*(*i)->name == name)) { // library found, import it and return. this->importSymbol(**i); return true; } } return false; } void SymbolTable::lateRegisterAttach( enum symType type, SymbolDeclaration &decl ) { DeclarativeRegion *current = this->getCurrentRegion(); assert(current); Symbol *sym = new Symbol(decl.name, type, current, decl); decl.region = current; DeclarativeRegion *check = current->parent; assert(check); this->popRegion(); DeclarativeRegion *above = this->getCurrentRegion(); assert(above == check); above->registerSymbol(sym); if (type == SYMBOL_TYPE) { RegisterBuiltins::regTypeOps(decl, *this); } this->pushRegion(*current); } void SymbolTable::flipStack(void) { DeclarativeRegion *top = this->getCurrentRegion(); assert(top); this->popRegion(); DeclarativeRegion *last = this->getCurrentRegion(); assert(last); this->popRegion(); DeclarativeRegion *check = this->getCurrentRegion(); assert(check); assert(last->parent == check); assert(top->parent == check); last->parent = top; this->pushRegion(*top); this->pushRegion(*last); } void SymbolTable::importSymbols(const DeclarativeRegion ®ion) { #if DEBUG std::cerr << "importSymbols: region.size()=" << region.declarations.size() << " at: " << ®ion << std::endl; #endif for (std::list::const_iterator i = region.declarations.begin(); i != region.declarations.end(); i++) { this->importSymbol(**i); } } DeclarativeRegion* SymbolTable::getCurrentRegion(void) const { if (this->regionStack.empty()) { return NULL; } return this->regionStack.top(); } void SymbolTable::pushStdStandard(void) { bool found = false; for (std::list::const_iterator i = this->libraries.begin(); i != this->libraries.end(); i++) { if (*(*i)->name == "std") { assert((*i)->region != NULL); this->regionStack.push((*i)->region); found = true; break; } } assert(found); /* builtin library std not found if assertion fails */ std::list p = this->lookup("standard"); assert(p.size() == 1); Symbol *ps = p.front(); assert(ps->type == SYMBOL_PACKAGE); // error in std.standard otherwise assert(ps->region != NULL); this->regionStack.push(ps->region); } TypeDeclaration* SymbolTable::getStdStandardType(const char *name) { typeMap::iterator i = this->stdStandardTypes.find(name); if (i == this->stdStandardTypes.end()) { // not found in cache this->pushStdStandard(); std::list l = this->lookup(name); this->popRegion(); // standard this->popRegion(); // std if (l.size() != 1) { return NULL; } Symbol *sym = l.front(); if (sym->type != SYMBOL_TYPE) { // not a type return NULL; } TypeDeclaration *t = dynamic_cast( &sym->declaration); if (! t) { return NULL; } this->stdStandardTypes[name] = t; return t; } return i->second; } std::string SymbolTable::getMangledPathName(void) const { static int cnt = 0; std::stringstream stream; stream << "__anonymous__"; // prefix stream << cnt; cnt++; std::string result = stream.str(); return result; } }; /* namespace ast */ fauhdlc-20130704/frontend/misc/StackTrace.hpp0000664000175000017500000000413611137610234020313 0ustar potyrapotyra/* $Id: StackTrace.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Helper to obtain the current stack trace. Should not be used in the actual * compiler (only there for debugging). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __STACK_TRACKE_HPP_DEFINED #define __STACK_TRACKE_HPP_DEFINED #include #include #include namespace ast { //! Helper to obtain the current stack trace. /** This class can be used to obtain the current (c++) stack trace. * It should not be used for anything in the compiler, apart from casual * debugging. * * To use this class, fauhdlc must be compiled with * -fno-omit-frame-pointers (otherwise g++ seems to omit frame pointers) * and * -rdynamic (to tell the linker to store all symbols in the dynamic symbol * table; otherwise name resolution will utterly fail). */ class StackTrace { public: //! obtain the current stack trace. /** @return instance filled with the current stack trace. */ static StackTrace *getStackTrace(void); /** actual stack trace (symbol names) */ std::list stackTrace; //! put the stack trace to a stream. void put(std::ostream &stream) const; private: //! dummy c'tor. use getStackTrace instead. StackTrace() {} //! resolve a symbol to the demangled entry. /** @param sym name of mangled symbol * @return name of demangled symbol (or sym in case demangling * doesn't succeed */ static std::string resolveSym(std::string sym); static std::map mangleMap; }; /** overloaded operator to conveniently output a StackTrace * @param stream stream to which a location should get written to. * @param st StackTrace instance to write to the stream. * @return modified stream */ std::ostream& operator <<(std::ostream &stream, const StackTrace &st); }; /* namespace ast */ #endif /* __STACK_TRACKE_HPP_DEFINED */ fauhdlc-20130704/frontend/misc/RegisterBuiltins.cpp0000664000175000017500000004206111502713264021562 0ustar potyrapotyra/* $Id: RegisterBuiltins.cpp 5087 2010-12-17 16:58:28Z potyra $ * * RegisterBuiltins: can register builtin functions for a given type * declaration. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/misc/RegisterBuiltins.hpp" #include #include #include #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/visitor/TopDownVisitor.hpp" #include "frontend/misc/SymbolTable.hpp" #include "frontend/reporting/CompileError.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/visitor/ResolveTypes.hpp" namespace ast { void RegisterBuiltins::regTypeOps(SymbolDeclaration &type, SymbolTable &s) { /* FIXME: deriving from NullVisitor is enough. However for debugging * purposes (no calls for wrong nodes, we'll stay with * TopDownVisitor). */ class Dispatcher : public TopDownVisitor { public: //! c'tor /** @param r RegisterBuiltins instance. */ Dispatcher(SymbolTable &st) : symTab(st) {} virtual void visit(RangeConstraintType &t) { if (t.baseType == BASE_TYPE_UNSET) { RegisterBuiltins::determineBaseType(t, this->symTab); } if (t.baseType == BASE_TYPE_UNSET) { // type error occured, bail out. return; } RegisterBuiltins::registerTypeOps(t, this->symTab); } virtual void visit(PhysicalType &t) { RegisterBuiltins::registerTypeOps(t, this->symTab); } virtual void visit(EnumerationType &t) { RegisterBuiltins::registerTypeOps(t, this->symTab); } virtual void visit(RecordType &t) { RegisterBuiltins::registerTypeOps(t, this->symTab); } virtual void visit(SubtypeIndication &t) { //skip. subtypes inherit operations of base types. } virtual void visit(UnconstrainedArrayType &t) { RegisterBuiltins::registerTypeOps(t, this->symTab); } private: // cppcheck-suppress unusedPrivateFunction (false positive) virtual void process(AstNode &t) { std::cerr << "BANG: found no type node: " << t << " at " << t.location << std::endl; assert(false); // not a type or no visit method for // given type in Dispatcher } SymbolTable &symTab; }; Dispatcher d = Dispatcher(s); type.accept(d); } void RegisterBuiltins::registerTypeOps(RangeConstraintType &type, SymbolTable &s) { /* FIXME split between integer and float types? */ if (type.baseType == BASE_TYPE_INTEGER) { // relational operators // equality, inequality: any type except file and protected RegisterBuiltins::boolBinOp("=", type, new BoolEqual(s), new GCBuiltinsEqual(), s); RegisterBuiltins::boolBinOp("/=", type, new BoolNotEqual(s), new GCBuiltinsInEqual(), s); // ordering: any scalar and discrete array (= 1-dim array of // discrete type) RegisterBuiltins::boolBinOp("<", type, new BoolLess(s), new GCBuiltinsLess(), s); RegisterBuiltins::boolBinOp("<=", type, new BoolLessOrEqual(s), new GCBuiltinsLessEqual(), s); RegisterBuiltins::boolBinOp(">", type, new BoolGreater(s), new GCBuiltinsGreater(), s); RegisterBuiltins::boolBinOp(">=", type, new BoolGreaterOrEqual(s), new GCBuiltinsGreaterEqual(), s); // adding operators (any numeric type) RegisterBuiltins::binOpSameType("+", type, new BinaryPlus(), new GCBuiltinsPlus(), s); RegisterBuiltins::binOpSameType("-", type, new BinaryMinus(), new GCBuiltinsMinus(), s); // (no concatenation for RangeConstraintType) // multiplying operators RegisterBuiltins::binOpSameType("*", type, new BinaryMult(), new GCBuiltinsMult(), s); RegisterBuiltins::binOpSameType("/", type, new BinaryDiv(), new GCBuiltinsDiv(), s); // sign operators (idendity, negation). Any numeric type. RegisterBuiltins::unOpSameType("+", type, new UnaryPlus(), new GCBuiltinsIdentity(), s); RegisterBuiltins::unOpSameType("-", type, new UnaryMinus(), new GCBuiltinsUnaryMinus(), s); RegisterBuiltins::unOpSameType("abs", type, new UnaryAbs(), new GCBuiltinsAnd(), s); // modulus/remainder RegisterBuiltins::binOpSameType("mod", type, new BinaryMod(), NULL, /* FIXME */ s); RegisterBuiltins::binOpSameType("rem", type, new BinaryRem(), NULL, /* FIXME */ s); } else { // relational operators // equality, inequality: any type except file and protected RegisterBuiltins::boolBinOp("=", type, new BoolEqual(s), new GCBuiltinsEqual(), s); RegisterBuiltins::boolBinOp("/=", type, new BoolNotEqual(s), new GCBuiltinsInEqual(), s); // ordering: any scalar and discrete array (= 1-dim array of // discrete type) RegisterBuiltins::boolBinOp("<", type, new BoolLess(s), new GCBuiltinsLess(), s); RegisterBuiltins::boolBinOp("<=", type, new BoolLessOrEqual(s), new GCBuiltinsLessEqual(), s); RegisterBuiltins::boolBinOp(">", type, new BoolGreater(s), new GCBuiltinsGreater(), s); RegisterBuiltins::boolBinOp(">=", type, new BoolGreaterOrEqual(s), new GCBuiltinsGreaterEqual(), s); // adding operators (any numeric type) RegisterBuiltins::binOpSameType("+", type, new BinaryPlus(), new GCBuiltinsPlus(), s); RegisterBuiltins::binOpSameType("-", type, new BinaryMinus(), new GCBuiltinsMinus(), s); // (no concatenation for RangeConstraintType) // multiplying operators RegisterBuiltins::binOpSameType("*", type, new BinaryMult(), new GCBuiltinsMult(), s); RegisterBuiltins::binOpSameType("/", type, new BinaryDiv(), new GCBuiltinsDiv(), s); // sign operators (idendity, negation). Any numeric type. RegisterBuiltins::unOpSameType("+", type, new UnaryPlus(), new GCBuiltinsIdentity(), s); RegisterBuiltins::unOpSameType("-", type, new UnaryMinus(), new GCBuiltinsUnaryMinus(), s); RegisterBuiltins::unOpSameType("abs", type, new UnaryAbs(), new GCBuiltinsAnd(), s); } // miscellaneous RegisterBuiltins::binOp("**", type, "integer", type, s); } void RegisterBuiltins::registerTypeOps(PhysicalType &type, SymbolTable &s) { // relational operators // equality, inequality: any type except file and protected RegisterBuiltins::boolBinOp("=", type, new BoolEqual(s), new GCBuiltinsEqual(), s); RegisterBuiltins::boolBinOp("/=", type, new BoolNotEqual(s), new GCBuiltinsInEqual(), s); // ordering: any scalar and discrete array (= 1-dim array of // discrete type) RegisterBuiltins::boolBinOp("<", type, new BoolLess(s), new GCBuiltinsLess(), s); RegisterBuiltins::boolBinOp("<=", type, new BoolLessOrEqual(s), new GCBuiltinsLessEqual(), s); RegisterBuiltins::boolBinOp(">", type, new BoolGreater(s), new GCBuiltinsGreater(), s); RegisterBuiltins::boolBinOp(">=", type, new BoolGreaterOrEqual(s), new GCBuiltinsGreaterEqual(), s); // adding operators (any numeric type) RegisterBuiltins::binOpSameType("+", type, new BinaryPlus(), new GCBuiltinsPlus(), s); RegisterBuiltins::binOpSameType("-", type, new BinaryMinus(), new GCBuiltinsMinus(), s); // (no concatenation for physical types) // sign operators (idendity, negation). Any numeric type. RegisterBuiltins::unOpSameType("+", type, new UnaryPlus(), new GCBuiltinsIdentity(), s); RegisterBuiltins::unOpSameType("-", type, new UnaryMinus(), new GCBuiltinsUnaryMinus(), s); // multiplying operators (physical types only) FunctionDeclaration *f; f = RegisterBuiltins::binOp("*", type, "integer", type, s); f->builtin = new BinaryMult(); f->gcBuiltin = new GCBuiltinsMult(); // FIXME builtins! RegisterBuiltins::binOp("*", type, "real", type, s); // int -> int -> int f = RegisterBuiltins::binOp("*", "integer", type, type, s); f->builtin = new BinaryMult(); f->gcBuiltin = new GCBuiltinsMult(); // FIXME builtins! RegisterBuiltins::binOp("*", "real", type, type, s); f = RegisterBuiltins::binOp("/", type, "integer", type, s); f->builtin = new BinaryDiv(); f->gcBuiltin = new GCBuiltinsDiv(); // FIXME builtins! RegisterBuiltins::binOp("/", type, "real", type, s); TypeDeclaration *univ_int = s.getStdStandardType("__universal_integer__"); RegisterBuiltins::binOp("/", type, type, *univ_int, s); // miscellaneous RegisterBuiltins::unOpSameType("abs", type, new UnaryAbs(), new GCBuiltinsAbs(), s); } void RegisterBuiltins::registerTypeOps( UnconstrainedArrayType &type, SymbolTable &s ) { // relational operators // equality, inequality: any type except file and protected // FIXME builtins RegisterBuiltins::boolBinOp("=", type, NULL, NULL, s); // FIXME builtins RegisterBuiltins::boolBinOp("/=", type, NULL, NULL, s); if (type.numIndices != 1) { return; } TypeDeclaration *elementType = type.elementType; assert(elementType != NULL); // concatenation (1-dim arrays) RegisterBuiltins::binOp("&", type, type, type, s); RegisterBuiltins::binOp("&", type, *elementType, type, s); RegisterBuiltins::binOp("&", *elementType, type, type, s); RegisterBuiltins::binOp("&", *elementType, *elementType, type, s); if (! RegisterBuiltins::isDiscreteType(elementType)) { return; } // ordering: any scalar and discrete array (= 1-dim array of // discrete type) // FIXME builtins RegisterBuiltins::boolBinOp("<", type, NULL, NULL, s); RegisterBuiltins::boolBinOp("<=", type, NULL, NULL, s); RegisterBuiltins::boolBinOp(">", type, NULL, NULL, s); RegisterBuiltins::boolBinOp(">=", type, NULL, NULL, s); if (! RegisterBuiltins::isBoolOrBit(elementType, s)) { return; } // shift operators (1-dim array of bool or bit) RegisterBuiltins::binOp("sll", type, "integer", type, s); RegisterBuiltins::binOp("srl", type, "integer", type, s); RegisterBuiltins::binOp("sla", type, "integer", type, s); RegisterBuiltins::binOp("sra", type, "integer", type, s); RegisterBuiltins::binOp("rol", type, "integer", type, s); RegisterBuiltins::binOp("ror", type, "integer", type, s); } void RegisterBuiltins::registerTypeOps(EnumerationType &type, SymbolTable &s) { // relational operators // equality, inequality: any type except file and protected RegisterBuiltins::boolBinOp("=", type, new BoolEqual(s), new GCBuiltinsEqual(), s); RegisterBuiltins::boolBinOp("/=", type, new BoolNotEqual(s), new GCBuiltinsInEqual(), s); // ordering: any scalar and discrete array (= 1-dim array of // discrete type) RegisterBuiltins::boolBinOp("<", type, new BoolLess(s), new GCBuiltinsLess(), s); RegisterBuiltins::boolBinOp("<=", type, new BoolLessOrEqual(s), new GCBuiltinsLessEqual(), s); RegisterBuiltins::boolBinOp(">", type, new BoolGreater(s), new GCBuiltinsGreater(), s); RegisterBuiltins::boolBinOp(">=", type, new BoolGreaterOrEqual(s), new GCBuiltinsGreaterEqual(), s); } void RegisterBuiltins::registerTypeOps(RecordType &type, SymbolTable &s) { // relational operators // equality, inequality: any type except file and protected // FIXME builtins RegisterBuiltins::boolBinOp("=", type, NULL, NULL, s); RegisterBuiltins::boolBinOp("/=", type, NULL, NULL, s); } SubtypeIndication* RegisterBuiltins::generateSubtypeIndic( const TypeDeclaration &type ) { SubtypeIndication *subtypeI = new SubtypeIndication(&type, Location("RegisterBuiltins.")); return subtypeI; } ConstantDeclaration* RegisterBuiltins::generateArgument( const TypeDeclaration &type, const SymbolTable &s ) { SubtypeIndication *si = RegisterBuiltins::generateSubtypeIndic(type); ConstantDeclaration *ret = new ConstantDeclaration( new std::string("__anonymous__"), NULL, /* initializier */ si, /* SubtypeIndication */ false, type.location); return ret; } FunctionDeclaration* RegisterBuiltins::boolBinOp( const char *declName, const TypeDeclaration &opType, BuiltinFunction *bf, GCBuiltins *gcBf, SymbolTable &s ) { TypeDeclaration *ret = s.getStdStandardType("boolean"); FunctionDeclaration *f = RegisterBuiltins::binOp(declName, opType, opType, *ret, s); f->builtin = bf; f->gcBuiltin = gcBf; return f; } FunctionDeclaration* RegisterBuiltins::binOpSameType( const char *declName, const TypeDeclaration &opType, BuiltinFunction *bf, GCBuiltins *gcBf, SymbolTable &s ) { FunctionDeclaration *f = RegisterBuiltins::binOp(declName, opType, opType, opType, s); f->builtin = bf; f->gcBuiltin = gcBf; return f; } FunctionDeclaration* RegisterBuiltins::unOpSameType( const char *declName, const TypeDeclaration &opType, BuiltinFunction *bf, GCBuiltins *gcBf, SymbolTable &s ) { std::string *n = new std::string(declName); std::list *args = new std::list(); args->push_back(RegisterBuiltins::generateArgument(opType, s)); FunctionDeclaration *ret = new FunctionDeclaration( n, // name of function args, // arguments RegisterBuiltins::generateSubtypeIndic(opType), true, // is pure? opType.location); ret->isBuiltin = true; ret->builtin = bf; ret->gcBuiltin = gcBf; s.registerSymbol(SYMBOL_FUNCTION, *ret); return ret; } FunctionDeclaration* RegisterBuiltins::binOp( const char *declName, const TypeDeclaration &left, const TypeDeclaration &right, const TypeDeclaration &returnT, SymbolTable &s ) { std::list *args = new std::list(); args->push_back(RegisterBuiltins::generateArgument(left, s)); args->push_back(RegisterBuiltins::generateArgument(right, s)); FunctionDeclaration *ret = new FunctionDeclaration( new std::string(declName), // name of function args, // arguments RegisterBuiltins::generateSubtypeIndic(returnT), true, // is pure? returnT.location); ret->isBuiltin = true; s.registerSymbol(SYMBOL_FUNCTION, *ret); return ret; } FunctionDeclaration* RegisterBuiltins::binOp( const char *declName, const char *left, const TypeDeclaration &right, const TypeDeclaration &returnT, SymbolTable &s ) { TypeDeclaration *l = s.getStdStandardType(left); return RegisterBuiltins::binOp(declName, *l, right, returnT, s); } FunctionDeclaration* RegisterBuiltins::binOp( const char *declName, const TypeDeclaration &left, const char *right, const TypeDeclaration &returnT, SymbolTable &s ) { TypeDeclaration *r = s.getStdStandardType(right); return RegisterBuiltins::binOp(declName, left, *r, returnT, s); } bool RegisterBuiltins::isDiscreteType(const TypeDeclaration *type) { // integer type or enumeration type. if (type == NULL) { return false; } const EnumerationType *et = dynamic_cast(type); if (et != NULL) { return true; } const RangeConstraintType *rt = dynamic_cast(type); if (rt == NULL) { return false; } switch(rt->baseType) { case BASE_TYPE_INTEGER: return true; case BASE_TYPE_REAL: return false; case BASE_TYPE_UNSET: return false; default: assert(false); } return false; } bool RegisterBuiltins::isBoolOrBit(const TypeDeclaration *type, SymbolTable &s) { const TypeDeclaration *reference = s.getStdStandardType("boolean"); if (reference == type) { return true; } reference = s.getStdStandardType("bit"); if (reference == type) { return true; } return false; } void RegisterBuiltins::determineBaseType(RangeConstraintType &t, SymbolTable &s) { ResolveTypes r = ResolveTypes(s); t.accept(r); } }; /* namespace ast */ fauhdlc-20130704/frontend/misc/BuiltinFunction.hpp0000664000175000017500000003660711137610234021413 0ustar potyrapotyra/* $Id: BuiltinFunction.hpp 4323 2009-01-27 13:48:12Z potyra $ * BuiltinFunction: inline implementation of a number of builtin functions like * operators. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __BUILTIN_FUNCTION_HPP_INCLUDED #define __BUILTIN_FUNCTION_HPP_INCLUDED #include #include #include "frontend/misc/BuiltinSymbolTable.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/TypeDeclaration.hpp" namespace ast { //! helper class for math of arbitrary universal types. class UniversalMath { public: //! calculate absolute value /** @param numeric value, for which abs should get calculated. * @return absolute value. */ template static T abs(T value) { if (value < 0) { return -value; } return value; } }; /** any builtin function should derive from this class. */ class BuiltinFunction { public: //! virtual dummy d'tor. virtual ~BuiltinFunction() {} /** execute the builtin returning the result. * @param args arguments for the builtin function. * @return result of the builtin */ virtual Expression* execute(std::list args) const = 0; }; //! any unary operand should implement this class /** Template parameter C: type of const node. * Template parameter V: value type of const node. */ template class BuiltinUnop : public BuiltinFunction { public: /** execute the builtin returning the result. * @param args arguments for the builtin function. * @return result of the builtin */ virtual Expression* execute(std::list args) const { assert(args.size() == 1); Expression *f = args.front(); C *constNode = dynamic_cast(f); assert(constNode != NULL); V result = this->executeUnop(constNode->value); C *rNode = new C(result, f->location); rNode->type = f->type; return rNode; } protected: /** execute the unary operator. * @param operand operand value. * @return value of the builtin. */ virtual V executeUnop(V operand) const = 0; }; //! any binary operand with same parameter should dervive from this class /** Template parameter C: type of const node. * Template parameter V: value type of const node. */ template class BuiltinBinOpSameType : public BuiltinFunction { public: /** execute the builtin returning the result. * @param args arguments for the builtin function. * @return result of the builtin */ virtual Expression* execute(std::list args) const { assert(args.size() == 2); Expression *l = args.front(); C *left = dynamic_cast(l); Expression *r = args.back(); C *right = dynamic_cast(r); assert(left != NULL); assert(right != NULL); V result = this->executeBinOp(left->value, right->value); C *resNode = new C(result, left->location); resNode->type = left->type; return resNode; } protected: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual V executeBinOp(V left, V right) const = 0; }; //! any binary operand with same parameter resulting in std.std.bool use this /** Template parameter C: type of const node. * Template parameter V: value type of const node. */ template class BoolBinOpSameType : public BuiltinFunction { public: /** c'tor * @param symTab SymbolTable instance (to look up std.std.boolean). */ BoolBinOpSameType(SymbolTable &symTab) : st(symTab) {} /** execute the builtin returning the result. * @param args arguments for the builtin function. * @return result of the builtin */ virtual Expression* execute(std::list args) const { assert(args.size() == 2); Expression *l = args.front(); C *left = dynamic_cast(l); Expression *r = args.back(); C *right = dynamic_cast(r); assert(left != NULL); assert(right != NULL); bool result = this->executeBinOp(left->value, right->value); universal_integer resVal = VHDL_FALSE; if (result) { resVal = VHDL_TRUE; } ConstInteger *resNode = new ConstInteger(resVal, left->location); TypeDeclaration *boolean = st.getStdStandardType("boolean"); resNode->type = new SubtypeIndication(boolean, boolean->location); return resNode; } protected: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual bool executeBinOp(V left, V right) const = 0; private: SymbolTable &st; }; //! unary minus template class UnaryMinus : public BuiltinUnop { private: /** execute the builtin returning the result. * @return result of this builtin. */ virtual V executeUnop(V operand) const { return - operand; } }; //! unary plus (identity) template class UnaryPlus : public BuiltinUnop { private: /** execute the builtin returning the result. * @return result of this builtin. */ virtual V executeUnop(V operand) const { return operand; } }; //! unary absolute value template class UnaryAbs : public BuiltinUnop { private: /** execute the builtin returning the result. * @return result of this builtin. */ virtual V executeUnop(V operand) const { if (operand < 0) { return - operand; } return operand; } }; //! binary plus template class BinaryPlus : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual V executeBinOp(V left, V right) const { // FIXME range check! return left + right; } }; //! binary minus template class BinaryMinus : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual V executeBinOp(V left, V right) const { // FIXME range check! return left - right; } }; //! binary multiplication template class BinaryMult : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual V executeBinOp(V left, V right) const { // FIXME range check! return left * right; } }; //! binary division template class BinaryDiv : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual V executeBinOp(V left, V right) const { return left / right; } }; //! binary modulo (only for integer types) class BinaryMod : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { //lrm, p.105: A = B * N + (A mod B) // sign of B, abs(A mod B) < abs(B) // // 5 % 4 // 4 * N + (mod) // 4 * 1 + 1 // // 5 % -4 // -4 * -2 + (-3) // // -5 % 4 // 4 * -2 + 3 // // -5 % -4 // -4 * 1 + (-1) // FIXME: right == 0 -> error assert(right != 0); if ((left > 0) && (right < 0)) { universal_integer tmp = UniversalMath::abs( left % UniversalMath::abs(right)); return right + tmp; } if ((left < 0) && (right > 0)) { universal_integer tmp = UniversalMath::abs( UniversalMath::abs(left) % right); return right - tmp; } universal_integer tmp = UniversalMath::abs( UniversalMath::abs(left) % UniversalMath::abs(right)); if (right < 0) { return -tmp; } return tmp; } }; //! binary remainder (only for integer types) class BinaryRem : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { //lrm, p. 104: A = (A/B) ∗ B +(A rem B) // A rem B has the sign of A and // a abs. value less than abs (B) // FIXME right == 0 -> error assert(right != 0); return left - ((left / right) * right); } }; //! universal equal operator template class BoolEqual : public BoolBinOpSameType { public: //! c'tor /** @param symTab SymbolTable instance */ BoolEqual(SymbolTable &symTab) : BoolBinOpSameType(symTab) {} private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual bool executeBinOp(V left, V right) const { return left == right; } }; //! universal not equal operator template class BoolNotEqual : public BoolBinOpSameType { public: //! c'tor /** @param symTab SymbolTable instance */ BoolNotEqual(SymbolTable &symTab) : BoolBinOpSameType(symTab) {} private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual bool executeBinOp(V left, V right) const { return left != right; } }; //! universal less than operator template class BoolLess : public BoolBinOpSameType { public: //! c'tor /** @param symTab SymbolTable instance */ BoolLess(SymbolTable &symTab) : BoolBinOpSameType(symTab) {} private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual bool executeBinOp(V left, V right) const { return left < right; } }; //! universal less or equal template class BoolLessOrEqual : public BoolBinOpSameType { public: //! c'tor /** @param symTab SymbolTable instance */ BoolLessOrEqual( SymbolTable &symTab ) : BoolBinOpSameType(symTab) {} private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual bool executeBinOp(V left, V right) const { return left <= right; } }; //! universal greater than operator template class BoolGreater : public BoolBinOpSameType { public: //! c'tor /** @param symTab SymbolTable instance */ BoolGreater(SymbolTable &symTab) : BoolBinOpSameType(symTab) {} private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual bool executeBinOp(V left, V right) const { return left > right; } }; //! universal greater or equal template class BoolGreaterOrEqual : public BoolBinOpSameType { public: //! c'tor /** @param symTab SymbolTable instance */ BoolGreaterOrEqual( SymbolTable &symTab ) : BoolBinOpSameType(symTab) {} private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual bool executeBinOp(V left, V right) const { return left >= right; } }; //! AND operator (bit, boolean) class EnumAND : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { if ((left == VHDL_TRUE) && (right == VHDL_TRUE)) { return VHDL_TRUE; } return VHDL_FALSE; } }; //! OR operator (bit, boolean) class EnumOR : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { if ((left == VHDL_TRUE) || (right == VHDL_TRUE)) { return VHDL_TRUE; } return VHDL_FALSE; } }; //! NAND operator (bit, boolean) class EnumNAND : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { if ((left == VHDL_TRUE) && (right == VHDL_TRUE)) { return VHDL_FALSE; } return VHDL_TRUE; } }; //! NOR operator (bit, boolean) class EnumNOR : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { if ((left == VHDL_TRUE) || (right == VHDL_TRUE)) { return VHDL_FALSE; } return VHDL_TRUE; } }; //! XOR operator (bit, boolean) class EnumXOR : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { if (left != right) { return VHDL_TRUE; } return VHDL_FALSE; } }; //! XNOR operator (bit, boolean) class EnumXNOR : public BuiltinBinOpSameType { private: /** execute the binary operator * @param left left operand * @param right right operand * @return value of the builtin. */ virtual universal_integer executeBinOp(universal_integer left, universal_integer right) const { if (left != right) { return VHDL_FALSE; } return VHDL_TRUE; } }; //! unary NOT (bit, boolean) class EnumNOT : public BuiltinUnop { private: /** execute the builtin returning the result. * @return result of this builtin. */ virtual universal_integer executeUnop(universal_integer operand) const { if (operand == VHDL_TRUE) { return VHDL_FALSE; } return VHDL_TRUE; } }; //! return a predefined value, to be used by enumeration types. class ReturnValue : public BuiltinFunction { public: //! c'tor. /** @param value this value will be returned on execution. * @param t type of the return value. */ ReturnValue( universal_integer value, const TypeDeclaration *t ) : val(value), type(t) {} /** execute the builtin returning the result. * @param args arguments for the builtin function. * @return the predefined value. */ virtual Expression* execute(std::list args) const { assert(args.empty()); ConstInteger *ret = new ConstInteger(this->val, Location("Builtin result")); ret->type = new SubtypeIndication(this->type, this->type->location); return ret; } private: //! value to return on execution. universal_integer val; //! corresponding type declaration const TypeDeclaration *type; }; }; #endif /* __BUILTIN_FUNCTION_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/NameLookup.hpp0000664000175000017500000001470311307447601020347 0ustar potyrapotyra/* $Id: NameLookup.hpp 4877 2009-12-08 13:07:13Z potyra $ * NameLookup: Knows about VHDL names and how/where to look these up in the * symboltable (i.e. it can e.g. switch the scope for prefixed names etc.) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NAME_LOOKUP_HPP_INCLUDED #define __NAME_LOOKUP_HPP_INCLUDED #include #include "frontend/misc/SymbolTable.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/Callable.hpp" #include "frontend/ast/NodeFactory.hpp" #include "frontend/reporting/CompileError.hpp" namespace ast { //! Glue class for SymbolTable while parsing. /** This class is a glue class between SymbolTable and the ParserDriver * used only for parsing. */ class NameLookup { public: //! c'tor /** @param symtab SymbolTable instance. */ NameLookup(SymbolTable &symtab); //! open the region associated with the symbol corresponding to name /** wrapper for symbol table to open the region associated with * the symbol name. Will report an error if the symbol doesn't have * an associated DeclarativeRegion. Will also report an error if the * name is not a SimpleName. * * @param name (Simple)Name with an associated Region. */ void openRegion(Name *name) throw(CompileError); //! shift the current lookup scope /** Shift the current lookup scope to the scope defined by prefix. * This is used to correctly look up the suffices of prefixed names. * This will only effect the very next symbol lookup via lookup. * @param prefix which refers to the current scope. * @param isFunction denotes the prefix a function name? */ void shiftScope(Name &prefix, bool isFunction); //! shift the current lookup scope to denote an attribute prefix. /** This function shifts the lookup scope to denote an attribute * prefix. The following lookups will return attribute names. * Reset with unshiftScope. */ void shiftAttributeScope(void); //! find or register the callable spec. /** Resolve the parameter (type) list of spec and look if there * is a conforming subprogram specification registered in the * SymbolTable already. If so, open its region, delete spec and * return the specification. If not, register spec and open its * region, and register the parameters. * * @param spec subprogram specification. * @return either the conformin specification or spec. */ Callable* findOrRegisterSubprog(Callable *spec); //! lookup the identifier id in the symbol table. /** @param id identifier to lookup. * @return list of candidate symbols (might be empty if not * found). */ std::list lookup(std::string &id) const; //! force to reset any scope lookups for expanded/selected names. /** Force undo any effect of shiftScope. */ void unshiftScope(void); //! generate either a selected or an expanded name /** @param prefix prefix of the selected or expanded name * @param suffix suffix of the selected or expanded name * @param candidates candidate symbols of the suffix * @param loc location of the suffix. * @return corresponding expanded or selected name */ Name* makeSelectedName( Expression *prefix, std::string *suffix, std::list candidates, Location loc) const; //! register lib clauses in symboltable. /** @param libs list of library clauses */ void registerLibClauses(const std::list &libs); //! register use clauses in symboltable. /** @param usecs list of use clauses. */ void registerUseClauses(const std::list &usecs); //! shift candidates by a subsription /** Shift the candidates cands by a subscription and return all * valid candidates. Also remove non-fitting candidates from * cands. * * @param cands prefix candidates * @param loc Location of the subscription (for error reporting only) * @return all possible shifted candidates */ static std::list shiftSubscriptCands(std::list &cands, Location loc); //! shift scope for a selected name /** shift scope for a selected name * * @param prefix prefix of the name. */ void shiftSelectedScope(Name &prefix); /** is the current resolved symbol an expanded name? */ bool isExpanded; private: /** shift one candidate by a subscription. * @param candidate prefix candidate * @return shifted symbol or NULL if subscription is not possible. */ static Symbol* shiftSubscriptCand(Symbol *candidate); //! shift scope for one symbol of a selected name /** shift scope for one candidate symbol of a selected name. * * @param prefixSym canidate symbol */ void shiftSelectedSym(Symbol *prefixSym); //! shift current lookup scope to an expanded name. /** @param sym symbol with a declarative region that gets * interpreted as an expanded name. */ void shiftExpanded(const Symbol &sym); //! symbol table instance. SymbolTable &symbolTable; /** list of possible scopes for which symbols should get looked up. * For expanded names which are not overloadable, this is the scope * of the expanded name prefix, for overloadable names it can * be more than one scope. For normal identifiers, this list should * be empty. */ std::list lookupScopes; /** Check two subprogram specifications that are procedure * specifications for conformance. * @param a first subprogram specification * @param b second subprogram specification * @return true if both conform. */ static bool conformProcSig(const Callable *a, const Callable *b); /** Check two FunctionDeclarations for conformance. * @param a first FunctionDeclaration * @param b second FunctionDeclaration * @return true if they conform, false otherwise. */ static bool conformFuncSig( const FunctionDeclaration *a, const FunctionDeclaration *b); /** check two ValDeclarations as part of subprogram specifications for * conformance. * * @param a first ValDeclaration * @param b second ValDeclaration * @return true if they conform. */ static bool conformParameter(const ValDeclaration *a, const ValDeclaration *b); /** was the scope shifted, and should hence shifted lookups * instead of regular symbol table lookups be performed? */ bool shiftedLookups; }; }; /* namespace ast */ #endif /* __NAME_LOOKUP_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/Symbol.hpp0000664000175000017500000001035611137610234017535 0ustar potyrapotyra/* $Id: Symbol.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Symbol: A symbol refers to a named entity. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SYMBOL_HPP_INCLUDED #define __SYMBOL_HPP_INCLUDED #include #include #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/SubtypeIndication.hpp" namespace ast { /** type of the symbol */ enum symType { /** symbol is an Entity */ SYMBOL_ENTITY = 1 << 0, /** symbol is a procedure declaration */ SYMBOL_PROCEDURE = 1 << 1, /** symbol is a function declaration */ SYMBOL_FUNCTION = 1 << 2, /** symbol is a signal declaration */ SYMBOL_SIGNAL = 1 << 3, /** symbol is a variable or constant declaration */ SYMBOL_VARIABLE = 1 << 4, /** symbol is a type declaration */ SYMBOL_TYPE = 1 << 5, /** symbol is a unit of a physical unit */ SYMBOL_UNIT = 1 << 6, /** symbol is an element of a record type */ SYMBOL_ELEMENT = 1 << 7, /** symbol is an attribute declaration */ SYMBOL_ATTRIBUTE = 1 << 8, /** symbol is an Architecture */ SYMBOL_ARCHITECTURE = 1 << 9, /** symbol is a Process */ SYMBOL_PROCESS = 1 << 10, /** symbol is a Loop label */ SYMBOL_LOOP = 1 << 11, /** symbol denotes a library */ SYMBOL_LIBRARY = 1 << 12, /** symbol denotes a package */ SYMBOL_PACKAGE = 1 << 13, /** pseudo symbol denoting "all" token */ SYMBOL_ALL = 1 << 14, /** symbol is a paramter */ SYMBOL_PARAMETER = 1 << 15, /** symbol is a port */ SYMBOL_PORT = 1 << 16 }; // forward declaration of DeclarativeRegion class DeclarativeRegion; //! symbol entry in the SymbolTable. /** The class Symbol represents one entry in the SymbolTable. * TODO path of symbol */ class Symbol { public: //! c'tor /** @param sname name of the Symbol * @param stype type of the Symbol. * @param decl reference to declaration. * @param reg DeclarativeRegion the Symbol belongs to. */ Symbol( const std::string* sname, enum symType stype, DeclarativeRegion* reg, SymbolDeclaration& decl ) : name(sname), type(stype), declaration(decl), region(reg) {} //! d'tor ~Symbol() { SymbolDeclaration* decl = &(this->declaration); util::MiscUtil::terminate(decl); } /** check if other is a Homograph of this. */ bool isHomograph(const Symbol& other) const; /** name of the symbol */ const std::string* name; /** type of the symbol */ enum symType type; /** referring declaration of the Symbol. */ SymbolDeclaration &declaration; /** possibly asssociated DeclarativeRegion of the symbol, * NULL possible. */ DeclarativeRegion *region; /** write the Symbol to stream. * @param stream write the symbol to this stream */ void put(std::ostream& stream) const; private: /** does the other symbol, which points to a callable have the * same parameter type profile (LRM 2.3)? * * @param other other symbol that points to a Callable. * @return true, if the other symbol has the same parameter type * profile, false otherwise. */ bool sameParameterProfile(const Symbol& other) const; /** does the other symbol, which points to a FunctionDeclaration * as well as this have the same result type profile? * * @param other other symbol that points to a FunctionDeclaration. * @return true if the result profile match, false otherwise. */ bool sameResultProfile(const Symbol& other) const; /** are the base types of given SubtypeIndication's equal? * Note: both SubtypeIndications need to have been resolved already. * * @param s1 first SubtypeIndication. * @param s2 second SubtypeIndication. * @return true if the base types are identical, false otherwise. */ static bool baseTypeEqual( const SubtypeIndication& s1, const SubtypeIndication& s2 ); }; /** write a symbol to a stream. * @param stream stream to which the symbol should get written to. * @param sym symbol that should get written. * @return modified stream. */ std::ostream& operator<<(std::ostream& stream, const Symbol& sym); }; /* namespace ast */ #endif /* __SYMBOL_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/RegisterBuiltins.hpp0000664000175000017500000001631711137610234021571 0ustar potyrapotyra/* $Id: RegisterBuiltins.hpp 4323 2009-01-27 13:48:12Z potyra $ * * RegisterBuiltins: can register builtin functions for a given type * declaration. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __REGISTER_BUILTINS_HPP_INCLUDED #define __REGISTER_BUILTINS_HPP_INCLUDED #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/misc/SymbolTable.hpp" #include "frontend/misc/BuiltinFunction.hpp" #include "frontend/visitor/GCBuiltins.hpp" namespace ast { //! register builtins for a given TypeDeclaration class RegisterBuiltins { public: /** register type operations for the given type. * @param type Type for which builtins should get registered. * @param s reference to the SymbolTable to which the type operations * should get registered to. */ static void regTypeOps(SymbolDeclaration &type, SymbolTable &s); private: /** register type operations for given type. * @param type RangeConstraintType for which builtins should get * registered. */ static void registerTypeOps(RangeConstraintType &type, SymbolTable &s); /** register type operations for given type. * @param type RangeConstraintType for which builtins should get * registered. * @param s reference to the SymbolTable to which the type operations * should get registered to. */ static void registerTypeOps(PhysicalType &type, SymbolTable &s); /** register type operations for given type. * @param type ArrayType for which builtins should get * registered. * @param s reference to the SymbolTable to which the type operations * should get registered to. */ static void registerTypeOps(UnconstrainedArrayType &type, SymbolTable &s); /** register type operations for given type. * @param type EnumerationType for which builtins should get * registered. * @param s reference to the SymbolTable to which the type operations * should get registered to. */ static void registerTypeOps(EnumerationType &type, SymbolTable &s); /** register type operations for given type. * @param type RecordType for which builtins should get * registered. * @param s reference to the SymbolTable to which the type operations * should get registered to. */ static void registerTypeOps(RecordType &type, SymbolTable &s); /** generate a SubtypeIndication from a TypeDeclaration matching * the very type. * @param type referring TypeDeclaration. * @return generated SubtypeIndication */ static SubtypeIndication* generateSubtypeIndic(const TypeDeclaration &type); /** generate one argument of given type for a builtin operator. * @param type type of the operand. * @param s SymbolTable instance. * @return ConstantDeclaration for parameter. */ static ConstantDeclaration* generateArgument(const TypeDeclaration &type, const SymbolTable &s); /** generate a binary operator function where the operands are of the * same type opType which results in the builtin boolean. * * @param declName name of the operator. * @param opType type that both operands need to have. * @param bf BuiltinFunction to use for ConstantPropagation * @param gcBf builtin inliner for code generation. * @param s reference to the SymbolTable to which the type operations * should get registered to. * @return generated operator function. */ static FunctionDeclaration* boolBinOp( const char *declName, const TypeDeclaration &opType, BuiltinFunction *bf, GCBuiltins *gcBf, SymbolTable &s); /** generate a binary operator function where the operand are of the * same type opType which results also in the same type opType. * * @param declName name of the operator * @param opType type of the operands and result type. * @param gcBf inline code generator for builtin. * @param bf builtin function for ConstantPropagation * @param s reference to the SymbolTable to which type operations * should get registered to. * @return generated operator function. */ static FunctionDeclaration* binOpSameType( const char *declName, const TypeDeclaration &opType, BuiltinFunction *bf, GCBuiltins *gcBf, SymbolTable &s); /** generate a unary operator function where the operand and the * result are of the type opType. * * @param declName name of the operator * @param opType type of the operand and result. * @param bf instance of BuiltinFunction for ConstantPropagation * @param gcBf instance of builtin inline code generator * @param s reference to the SymbolTable to which type operations * should get registered to. * @return generated operator function. */ static FunctionDeclaration* unOpSameType( const char *declName, const TypeDeclaration &opType, BuiltinFunction *bf, GCBuiltins *gcBf, SymbolTable &s); /** generate a binary operator and register it in the SymbolTable. * @param declName name of the operator. * @param left type of left operand. * @param right type of right operand. * @param return return type. * @param s SymbolTable instance. */ static FunctionDeclaration* binOp( const char *declName, const TypeDeclaration &left, const TypeDeclaration &right, const TypeDeclaration &returnT, SymbolTable &s ); /** generate a binary operator and register it in the SymbolTable. * @param declName name of the operator. * @param left type of left operand (member of std.standard). * @param right type of right operand. * @param return return type. * @param s SymbolTable instance. */ static FunctionDeclaration* binOp( const char *declName, const char *left, const TypeDeclaration &right, const TypeDeclaration &returnT, SymbolTable &s ); /** generate a binary operator and register it in the SymbolTable. * @param declName name of the operator. * @param left type of left operand. * @param right type of right operand (member of std.standard). * @param return return type. * @param s SymbolTable instance. */ static FunctionDeclaration* binOp( const char *declName, const TypeDeclaration &left, const char *right, const TypeDeclaration &returnT, SymbolTable &s ); /** check, if type is a discrete type. * @param type type to check. * @return true, if it is a discrete type. */ static bool isDiscreteType(const TypeDeclaration *type); /** check, if type is either std.standard.boolean or std.standard.bit * @param type type to check. * @param s SymbolTable instance. * @return true if type is either boolean or bit. */ static bool isBoolOrBit(const TypeDeclaration *type, SymbolTable &s); /** check if t is a integer or float type and set the baseType * accordingly. * * @param t RangeConstraintType that will get the baseType set. * @param s SymbolTable instance. */ static void determineBaseType(RangeConstraintType &t, SymbolTable &s); }; }; /* namespace ast */ #endif fauhdlc-20130704/frontend/misc/SymbolTable.hpp0000664000175000017500000001237411307471226020514 0ustar potyrapotyra/* $Id: SymbolTable.hpp 4881 2009-12-08 15:36:54Z potyra $ * * SymbolTable: Raw storage facility for symbols. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SYMBOL_TABLE_HPP_INCLUDED #define __SYMBOL_TABLE_HPP_INCLUDED #include #include #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/Library.hpp" #include "frontend/misc/Symbol.hpp" #include "frontend/misc/DeclarativeRegion.hpp" namespace ast { //! manage symbols. class SymbolTable { public: /** c'tor. */ SymbolTable(); /** d'tor */ virtual ~SymbolTable(); /** register a symbol with name name and type type in the current * DeclarativeRegion. This method will indirectly report an error * via the associated DeclarativeRegion method. * * @param type Type of the symbol. * @param decl reference to the actually declared symbol. * @return registered Symbol. */ Symbol* registerSymbol( enum symType type, SymbolDeclaration &decl); /** register a symbol in the current region, starting a new * declarative Region with the Symbol. Use-case: Entity, Package, ... * * @param type Type of the Symbol. * @param decl reference to the actually declared symbol. */ void registerSymbolWithRegion( enum symType type, SymbolDeclaration &decl); /** create a new region and push it onto the stack. should be * called when entering a nested declarative region. * */ virtual void pushNewRegion(void); /** If the library doesn't appear yet in the library list, * create a new declarative region for given library and push it * on the stack. Otherwise fetch the region of the library and * push this on the stack. * Register given library in the library list if not yet present. * * @param node Library that should get entered. */ void pushLibrary(Library &node); /** push the DeclarativeRegion region on the stack. * @param region DeclarativeRegion that should get pushed on the * stack. */ void pushRegion(DeclarativeRegion ®ion); /** remove the current region from the stack and make the next * outer region the current one. Should be called when leaving * a declarative region. */ void popRegion(void); /** lookup symbol by name. Stack mustn't be empty for this. * @param name search for this name. * @return visible candidates for given symbol. */ std::list lookup(const std::string &name) const; /** add given symbol to imported symbols of current region, * in case it's not in there yet. * * @param sym symbol to import. */ void importSymbol(Symbol &sym); /** import all symbols from region * @param region DeclarativeRegion from which all declarations * should get imported. */ void importSymbols(const DeclarativeRegion ®ion); /** add library with name name to the currently imported symbols, * register an error if library cannot be found. * * @param name name of the library. * @return true on success, false if library was not found. */ bool addlibrary(const std::string &name); /** register the symbol decl as the symbol to which the current * opened declarative region is attached to. The current region * should be an anonymous one. * * @param type type of the symbol * @param decl symbol declaration. */ void lateRegisterAttach(enum symType type, SymbolDeclaration &decl); /** region stack needs to have at least two entries. Rebind * top-1 to have top as parent. Flip top and top-1 on the stack. */ void flipStack(void); /** find out about the current declarative region. * @return current declarative region or NULL. */ DeclarativeRegion* getCurrentRegion(void) const; /** return a type of std.standard * @param name of the type declaration that should be looked up in * std.standard. * @return fitting type declaration or NULL if there is no such * declaration. */ TypeDeclaration *getStdStandardType(const char *name); /** determine the current path name, mangled so that delimiters are * two underscores. * @return current path name. * * TODO dummy implementation atm, which will just return a * unique name. */ std::string getMangledPathName(void) const; /** push the library std on the stack, then the package standard. */ void pushStdStandard(void); /** Obtain the hidden region in which builtin attributes reside. * @return hidden region in which builtin attributes reside. */ DeclarativeRegion * getAttributeRegion(void) const { return this->attributeRegion; } protected: /** stack of current open regions, top (last) is current region. */ std::stack regionStack; /** region in which attributes reside */ DeclarativeRegion *attributeRegion; private: /** list of known libraries (Symbols referring to libraries) */ std::list libraries; /** typedef for type mappings */ typedef std::map typeMap; /** chache for type lookups in std.standard. */ typeMap stdStandardTypes; }; }; /* namespace ast */ #endif /* __SYMBOL_TABLE_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/RangeSet.hpp0000664000175000017500000001334411137610234020000 0ustar potyrapotyra/* $Id: RangeSet.hpp 4323 2009-01-27 13:48:12Z potyra $ * * RangeSet defines operation for a Range and sets of ranges, like checking if * one range is a subset of another. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RANGE_SET_HPP_INCLUDED #define __RANGE_SET_HPP_INCLUDED #include #include #include "frontend/ast/Types.hpp" #include "frontend/ast/DiscreteRange.hpp" namespace ast { //! operation on ranges / sets of ranges. /** The class RangeSet is useful to determine subsets of ranges and * being able to iterate over those. */ class RangeSet { public: //! c'tor /** @param l left bound of the RangeSet. * @param r right bound of the RangeSet. * l <= r must be true. */ RangeSet(universal_integer l, universal_integer r); //! alternate c'tor /** construct from DiscreteRange. * @param dr source discrete range. Must not be a NULL range. */ RangeSet(const DiscreteRange &dr); /** substract a range from l to r from the current range. * @param l left bound of the range to substract. * @param r right bound of the range to substract. * @return true, if [l, r] is a subset of this Range, false * otherwise. * l <= r must be true. */ bool minus(universal_integer l, universal_integer r); /** substract a range from the current range. * Does the same as the other minus, just for a DiscreteRange. * @param dr range to substract. Must not be a null range. * @return true if [l, r] is a subset of this Range, false * otherwise. */ bool minus(const DiscreteRange &dr); /** unify with given Range. * @param dr DiscreteRange to unify with. */ void plus(const DiscreteRange &dr); /** unify with a range from l to r. * @param l left bound of the range. * @param r right bound of the range. * l <= r must be true. */ void plus(universal_integer l, universal_integer r); /** is the range set empty? * @return true, if there are no ranges in the set. */ bool empty(void) const; /** clear all elements from the RangeSet. */ void clear(void); /** put a textual representation of the RangeSet to stream. * @param stream target stream to put RangeSet to. */ void put(std::ostream &stream) const; /** return the upper bound. * Must not be called, when empty is true. * @return highest number still part of the Range. */ universal_integer getUpperBound(void) const; /** return the lower bound. * Must not be called, when empty is true. * @return lowest number still part of the Range. */ universal_integer getLowerBound(void) const; /** is value part of the RangeSet? */ bool contains(universal_integer value) const; private: /** a single range. */ class Range { public: /** c'tor. * The following must be true: l <= r * @param l left bound of the range (part of the range). * @param r right bound of the range (part of the range). */ Range(universal_integer l, universal_integer r); /** calculate the distance from this to other. * @param number of empty fields between this and other. * Negative numbers mean that other is left of * this, positive numbers mean that it is right * of this. 0 means that the ranges are adjacent or * overlap. */ universal_integer distance(const Range &other) const; /** is this a subset of other? * @param other check if this is a subset other. * @return true, if it is a subset, false if not. It will * also return true, other is equal to this * (non-true subset). */ bool isSubset(const Range &other) const; /** is the value inside the Range? * @param value value to check if inside the Range. * @return true if value is inside the Range, false otherwise. */ bool contains(universal_integer value) const; /** is this equal to other? * @param other range to check for equality. * @return true, if both bounds match, false otherwise. */ bool operator ==(const Range &other) const; /** is this Range left of the other range? * @param other other range to check. * @return true, if this Range is left of the other * Range. In particular an overlapping Range is * not considered left of. */ bool operator <(const Range &other) const; /** is this Range right of the other range? * @param other other range to check. * @return true, if this Range is right of the other * Range. In particular an overlapping Range is * not considered right of. */ bool operator >(const Range &other) const; /** substract other from this range. * @param other range to substract from this range. * @return list containing 0, 1 or 2 ranges (depending * if is equal to this, has one common boundary or * is a true subset of this with no common boundary. */ std::list operator -(const Range &other) const; /** put a textual representation of the Range to stream. * @param stream target stream to put Range to. */ void put(std::ostream &stream) const; /** left bound of the range. */ universal_integer left; /** right bound of the range. */ universal_integer right; }; //! list of different ranges forming this RangeSet. std::list ranges; }; //! overloaded << operator to easily output a RangeSet /** @param stream stream to put a rs to. * @param rs put rs to stream. * @return modified stream. */ std::ostream & operator <<(std::ostream &stream, const RangeSet &rs); }; /* namespace ast */ #endif /* __RANGE_SET_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/DeclarativeRegion.hpp0000664000175000017500000000605611137610234021661 0ustar potyrapotyra/* $Id: DeclarativeRegion.hpp 4323 2009-01-27 13:48:12Z potyra $ * * DeclarativeRegion: One pocket to store symbols. Can be chained together. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DECLARATIVE_REGION_HPP_INCLUDED #define __DECLARATIVE_REGION_HPP_INCLUDED #include #include #include "frontend/misc/Symbol.hpp" namespace ast { //! one declarative region class DeclarativeRegion { public: //! c'tor /** * @param p link to parent declarative region, NULL in case * it's a library declarative region. */ DeclarativeRegion(DeclarativeRegion *p); /** d'tor */ ~DeclarativeRegion(); /** register symbol sym to declarations. * @param sym Symbol that should get registered. */ void registerSymbol(Symbol *sym); /** lookup name symbol by name. * @param name search for this name. * @return visible candidates for given symbol. */ std::list lookup(const std::string &name) const ; /** check if sym is the symbol of an enclosing region * @param sym symbol to check. * @return true, if sym declares a region which encloses * this region. */ bool isEnclosingSymbol(const Symbol &sym) const; /** symbols declared in this region */ std::list declarations; /** symbols visible through use-clauses */ std::list imports; /** parent declarative region */ DeclarativeRegion *parent; // FIXME potyra: use a better storage facility than just an // unordered list. Maybe a hashtable or s.th. like that. /** lookup name symbol by name, only in current DeclarativeRegion, * not considering imported symbols. * @param name search for this name * @return candidates for given symbol of local region. */ std::list lookupLocal(const std::string &name) const; private: /** check if this region contains a Homograph to * symbol sym already. * @param sym check for a Homograph of this symbol. * @return the Symbol, which is a Homograph or NULL if * no Homograph exists. */ const Symbol* containsHomograph(const Symbol &sym) const; /** recursively search (parent) declarative regions * that resolve the symbol with name. * @param name name to look for. * @param candidates list of Symbols which are candidates to * resolve given name. */ void lookupRec( const std::string &name, std::list &candidates ) const; /** check if symbol sym is visible in the context of a set of * possible homographs. * @param sym contains the symbol for which visibility should get * checked. * @param check list of symbols, which possibly hide sym. * @return true if the symbol is visible. */ bool isVisible( const Symbol &sym, const std::list &check ) const; }; }; /* namespace ast */ #endif /* __DECLARATIVE_REGION_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/BuiltinSymbolTable.hpp0000664000175000017500000000674611307462617022055 0ustar potyrapotyra/* $Id: BuiltinSymbolTable.hpp 4879 2009-12-08 14:41:19Z potyra $ * * BuiltinSymbolTable: SymbolTable preloaded with symbols from std.standard. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __BUILTIN_SYMBOL_TABLE_HPP_INCLUDED #define __BUILTIN_SYMBOL_TABLE_HPP_INCLUDED #include "frontend/misc/SymbolTable.hpp" namespace ast { /** boolean values as represented in the builtin symbol table * note: true is 0 in vhdl */ enum vhdl_bool_vals { /** integer value of boolean false in VHDL */ VHDL_FALSE = 0, /** integer value of boolean true in VHDL */ VHDL_TRUE = 1, }; //! the SymbolTable with predefined internal symbols. /** This class predefines all symbols from std.standard. * (or at least to the extent the current implementation for the framework * allows). */ class BuiltinSymbolTable : public SymbolTable { public: //! c'tor BuiltinSymbolTable(); /** create a new region and push it onto the stack. should be * called when entering a nested declarative region. * * If the regionStack has the size 1, it must be a library unit. * Hence the library std and the package standard will be made * visible. */ virtual void pushNewRegion(void); private: /** register all builtins of std.standard. * Will call addStandardStd to add the actual * symbols. * */ void registerBuiltinSymbols(void); /** add all symbols of std.standard. SymbolTable needs to * have entered the package standard of library std already. * * @param standardSyms (empty) list to which all declarations * should get attached to (to be correctly stored in the * AST). */ void addStandardStd(std::list &standardSyms); /** add all internal attributes to __attributes__ */ void addAttributes(void); /** add time to std.standard. * @param standardSyms list of package symbols of standard */ void addStdStandardTime(std::list &standardSyms); /** register a physical type unit in std.standard */ void addPhysUnit( std::list &standardSyms, std::list &units, const char *name, universal_integer factor, const char *refName ); /** add character enumeration literal c to Enumeration element list. * @param elems list of enumeration elements * @param c character literal */ static void addEnumChar(std::list &elems, char c); /** add string enumeration literal s to Enumeration element list. * @param elems list of enumeration elements * @param c string literal. */ static void addEnumStr(std::list &elems, const char *s); /** register the "foreign" attribute * @param stringT type declaration of "string" * @param standardSyms list of packages symbols of standard */ void addForeignAttribute( const TypeDeclaration *stringT, std::list &standardSyms); /** register given attribute. * @param name name of the attribute * @param stdType return type (in std.standard) of the * attribute. */ void addAttributeDecl( const char *name, const char *stdType); /** should we import std.standard when registering a LibUnit? */ bool mayAddStdStandard; }; }; /* namespace ast */ #endif /* __BUILTIN_SYMBOL_TABLE_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/RangeSet.cpp0000664000175000017500000001301311137610234017764 0ustar potyrapotyra/* $Id: RangeSet.cpp 4323 2009-01-27 13:48:12Z potyra $ * * RangeSet defines operation for a Range and sets of ranges, like checking if * one range is a subset of another. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include "frontend/misc/RangeSet.hpp" namespace ast { /* **************** nested class Range **************** */ RangeSet::Range::Range( universal_integer l, universal_integer r ) : left(l), right(r) { assert(l <= r); } universal_integer RangeSet::Range::distance(const Range &other) const { if (this->right < other.left) { return this->right - other.left; } if (other.right < this->left) { return this->left - other.right; } return 0; } bool RangeSet::Range::isSubset(const Range &other) const { if ((other.left <= this->left) && (other.right >= this->right)) { return true; } return false; } bool RangeSet::Range::contains(universal_integer value) const { return (value <= this->right) && (this->left <= value); } bool RangeSet::Range::operator ==(const Range &other) const { return (this->left == other.left) && (this->right == other.right); } bool RangeSet::Range::operator <(const Range &other) const { return this->left < other.right; } bool RangeSet::Range::operator >(const Range &other) const { return other.left < this->right; } std::list RangeSet::Range::operator -(const Range &other) const { std::list ret; if (! other.isSubset(*this)) { return ret; } if (other == *this) { return ret; } // true subset if (this->left < other.left) { Range r = Range(this->left, other.left - 1); ret.push_back(r); } if (other.right < this->right) { Range r = Range(other.right + 1, this->right); ret.push_back(r); } return ret; } void RangeSet::Range::put(std::ostream &stream) const { if (this->left < this->right) { stream << '[' << this->left << ", " << this->right << ']'; } else { // range with only one element. stream << this->left; } } /* ******************** RangeSet ******************** */ RangeSet::RangeSet( universal_integer l, universal_integer r ) { Range initial = Range(l, r); this->ranges.push_back(initial); } RangeSet::RangeSet(const DiscreteRange &r) { if (r.getLowerBound() <= r.getUpperBound()) { Range initial = Range(r.getLowerBound(), r.getUpperBound()); this->ranges.push_back(initial); } } bool RangeSet::minus(const DiscreteRange &r) { return this->minus(r.getLowerBound(), r.getUpperBound()); } bool RangeSet::minus(universal_integer l, universal_integer r) { Range sub = Range(l, r); bool found = false; std::list::iterator i; for (i = this->ranges.begin(); i != this->ranges.end(); i++) { if (sub.isSubset(*i)) { found = true; break; } } if (! found) { return false; } std::list ret = (*i) - sub; i = this->ranges.erase(i); if (! ret.empty()) { this->ranges.insert(i, ret.begin(), ret.end()); } return true; } void RangeSet::plus(const DiscreteRange &dr) { this->plus(dr.getLowerBound(), dr.getUpperBound()); } void RangeSet::plus(universal_integer l, universal_integer r) { assert(l <= r); Range nr = Range(l, r); universal_integer lb = l; universal_integer ub = r; std::list::iterator i1 = this->ranges.begin(); std::list::iterator i2; // i1 : first range that is at least directly adjacent left to nr, // or is anywhere right of that place (e.g. overlapping or // right of nr). while ((i1 != this->ranges.end()) && (i1->distance(nr) < -1)) { i1++; } i2 = i1; // i2 : first range that is at least not adjacent right of nr, // i.e. it doesn't overlap and isn't left of nr. while ((i2 != this->ranges.end()) && (i2->distance(nr) < 2)) { if (i2->right > ub) { ub = i2->right; } i2++; } if (i1 == this->ranges.end()) { // no ranges that overlap or are right of r or are // adjacent. // -> just insert at end. this->ranges.push_back(nr); return; } if (i1->left < lb) { lb = i1->left; } // i1 == i2 -> there are no overlapping/adjacent ranges, // as i1 is right of r if (i1 == i2) { assert((*i1) > nr); this->ranges.insert(i1, nr); return; } // [i1, i2) are all overlapping (or form with the new range an // a complete range). // lb, ub are the lowest and highest bound of r and [i1, i2). i1 = this->ranges.erase(i1, i2); this->ranges.insert(i1, Range(lb, ub)); } bool RangeSet::empty(void) const { return this->ranges.empty(); } void RangeSet::clear(void) { this->ranges.clear(); } universal_integer RangeSet::getUpperBound(void) const { assert(! this->ranges.empty()); return this->ranges.back().right; } universal_integer RangeSet::getLowerBound(void) const { assert(! this->ranges.empty()); return this->ranges.front().left; } void RangeSet::put(std::ostream &stream) const { stream << "{ "; for (std::list::const_iterator i = this->ranges.begin(); i != this->ranges.end(); i++) { if (i != this->ranges.begin()) { stream << ", "; } i->put(stream); } stream << " }"; } bool RangeSet::contains(universal_integer value) const { for (std::list::const_iterator i = this->ranges.begin(); i != this->ranges.end(); i++) { if (i->contains(value)) { return true; } } return false; } std::ostream & operator <<(std::ostream &stream, const RangeSet &rs) { rs.put(stream); return stream; } }; /* namespace ast */ fauhdlc-20130704/frontend/misc/StackTrace.cpp0000664000175000017500000000633611137610234020312 0ustar potyrapotyra/* $Id: StackTrace.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Helper to obtain the current stack trace. Should not be used in the actual * compiler (only there for debugging). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/misc/StackTrace.hpp" #include #include extern "C" { #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include static void * __attribute__((always_inline)) getStackElement( void *frame_pointer, const char **entry ) { void **fp = reinterpret_cast(frame_pointer); void *return_address; void *old_fp; int ret; Dl_info info; old_fp = *fp; fp++; return_address = *fp; ret = dladdr(return_address, &info); if (ret == 0) { return NULL; } *entry = info.dli_sname; return old_fp; } #if defined(__i386__) static void * __attribute__((always_inline)) getFramePointer(void) { void *fp; asm ( "mov %%ebp, %0;" : "=r"(fp) /* output */ : /* no input */ : /* nothing clobbered */ ); return fp; } /* __i386__ */ #elif defined(__x86_64__) static void * __attribute__((always_inline)) getFramePointer(void) { void *fp; asm ( "mov %%rbp, %0;" : "=r"(fp) /* output */ : /* no input */ : /* nothing clobbered */ ); return fp; } #else /* ! __x86_64__ */ #error Not ported yet. #endif const char * demangle(const char *sym) { static char cmd[4096]; unsigned int ret; FILE *fp; char *s; ret = snprintf(cmd, sizeof(cmd), "/usr/bin/c++filt \"%s\"", sym); assert(ret < sizeof(cmd)); fp = popen(cmd, "r"); if (fp == NULL) { return sym; } s = fgets(cmd, sizeof(cmd), fp); if (s == NULL) { pclose(fp); return sym; } pclose(fp); return cmd; } }; /* extern "C" */ namespace ast { std::map StackTrace::mangleMap = std::map(); StackTrace * StackTrace::getStackTrace(void) { void *fp; const char *symbol; StackTrace *strace; std::string demangled_sym; strace = new StackTrace(); fp = getFramePointer(); while (fp != NULL) { fp = getStackElement(fp, &symbol); if (fp != NULL) { demangled_sym = resolveSym(std::string(symbol)); strace->stackTrace.push_back(demangled_sym); } } return strace; } void StackTrace::put(std::ostream &stream) const { stream << "Stack trace:" << std::endl; for (std::list::const_iterator i = this->stackTrace.begin(); i != this->stackTrace.end(); i++) { stream << "\t" << *i; } } std::string StackTrace::resolveSym(std::string sym) { std::map::const_iterator i = StackTrace::mangleMap.find(sym); if (i != StackTrace::mangleMap.end()) { return i->second; } // resolve + insert into mangle map. const char *res; res = demangle(sym.c_str()); if (res != NULL) { mangleMap[sym] = std::string(res); return std::string(res); } // resolution not possible mangleMap[sym] = sym; return sym; } std::ostream& operator <<(std::ostream &stream, const StackTrace &st) { st.put(stream); return stream; } }; /* namespace ast */ fauhdlc-20130704/frontend/misc/NameLookup.cpp0000664000175000017500000002634411307471226020346 0ustar potyrapotyra/* $Id: NameLookup.cpp 4881 2009-12-08 15:36:54Z potyra $ * NameLookup: Knows about VHDL names and how/where to look these up in the * symboltable (i.e. it can e.g. switch the scope for prefixed names etc.) * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/misc/NameLookup.hpp" #include "frontend/misc/Symbol.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "util/MiscUtil.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/reporting/CompileError.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/reporting/UndefinedSymbol.hpp" #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/visitor/LookupTypes.hpp" #include #include namespace ast { NameLookup::NameLookup( SymbolTable &symtab ) : symbolTable(symtab), shiftedLookups(false) { } void NameLookup::openRegion(Name *name) throw(CompileError) { const SimpleName *sname = dynamic_cast(name); assert(sname != NULL); /* logic error in parser */ if (sname->candidates.size() > 1) { std::string msg = "Multiple definitions for Name '"; msg += util::MiscUtil::toString(*name); msg += "'."; throw CompileError(*name, msg); } if (sname->candidates.empty()) { std::string msg = "Cannot find definition for Name '"; msg += util::MiscUtil::toString(*name); msg += "'."; throw CompileError(*name, msg); } const Symbol *sym = sname->candidates.front(); assert(sym->region != NULL); // logic error in parser this->symbolTable.pushRegion(*sym->region); } void NameLookup::shiftScope(Name &prefix, bool isFunction) { this->shiftedLookups = true; //LRM: 6.3 // hit by preference? symbol is an enclosing named entity // -> expanded name, nothing else considered. for(std::list::const_iterator i = prefix.candidates.begin(); i != prefix.candidates.end(); i++) { const DeclarativeRegion *current = this->symbolTable.getCurrentRegion(); assert(current != NULL); if (current->isEnclosingSymbol(**i)) { //immediate hit. this->shiftExpanded(**i); return; } } // is the prefix a function call? -> only selected name possible if (isFunction) { this->shiftSelectedScope(prefix); return; } // does the prefix denote a library/package? if (prefix.candidates.size() == 1) { switch(prefix.candidates.front()->type) { case SYMBOL_PACKAGE: case SYMBOL_LIBRARY: this->shiftExpanded(*prefix.candidates.front()); return; default: break; } } //remaining symbols must be selected names this->shiftSelectedScope(prefix); } void NameLookup::shiftAttributeScope(void) { assert(this->lookupScopes.empty()); DeclarativeRegion *hidden = this->symbolTable.getAttributeRegion(); this->lookupScopes.push_back(hidden); this->shiftedLookups = true; } ast::Callable* NameLookup::findOrRegisterSubprog(Callable* spec) { enum symType t = SYMBOL_PROCEDURE; switch(spec->kind) { case SubprogBody::PROG_KIND_PROCEDURE: t = SYMBOL_PROCEDURE; break; case SubprogBody::PROG_KIND_FUNCTION: t = SYMBOL_FUNCTION; break; default: assert(false); } /* lookup if specification registered already. */ assert(spec->name); bool found = false; Callable *c = NULL; std::list ret = this->symbolTable.lookup(*spec->name); for (std::list::const_iterator i = ret.begin(); i != ret.end(); i++) { if ((*i)->type != t) { continue; } switch(spec->kind) { case SubprogBody::PROG_KIND_PROCEDURE: c = dynamic_cast(&(*i)->declaration); found = this->conformProcSig(spec, c); break; case SubprogBody::PROG_KIND_FUNCTION: { FunctionDeclaration *f; FunctionDeclaration *g; f = dynamic_cast( &(*i)->declaration); assert(f); g = dynamic_cast(spec); assert(g); found = this->conformFuncSig(g, f); c = f; break; } default: assert(false); } if (found) { break; } } if (! found) { this->symbolTable.registerSymbolWithRegion(t, *spec); if (spec->arguments == NULL) { return spec; } //register formals for (std::list::const_iterator i = spec->arguments->begin(); i != spec->arguments->end(); i++) { this->symbolTable.registerSymbol(SYMBOL_PARAMETER, **i); } return spec; } assert(c != NULL); assert(c->region != NULL); this->symbolTable.pushRegion(*c->region); c->seen = true; return c; } std::list NameLookup::lookup(std::string &id) const { if (! this->shiftedLookups) { assert(this->lookupScopes.empty()); return this->symbolTable.lookup(id); } std::set unionSet = std::set(); for (std::list::const_iterator i = this->lookupScopes.begin(); i != this->lookupScopes.end(); i++) { std::list lu = (*i)->lookupLocal(id); if (! lu.empty()) { unionSet.insert(lu.begin(), lu.end()); } } std::list ret; ret.insert(ret.end(), unionSet.begin(), unionSet.end()); return ret; } void NameLookup::unshiftScope(void) { this->lookupScopes.clear(); this->shiftedLookups = false; } Name* NameLookup::makeSelectedName( Expression *prefix, std::string *suffix, std::list candidates, Location loc) const { if (this->isExpanded) { SimpleName *s = dynamic_cast(prefix); assert(s); // otherwise isExpanded is wrong SimpleName *ret = new SimpleName(suffix, candidates, loc); if (*suffix == "all") { //store candidates of prefix, to be used for use //clauses ret->candidates = s->candidates; } ret->prefixStrings = s->prefixStrings; ret->prefixStrings.push_back(s->name); s->name = NULL; s->prefixStrings.clear(); util::MiscUtil::terminate(s); return ret; } //selected name return new SelectedName(suffix, prefix, candidates, loc); } void NameLookup::registerLibClauses(const std::list &libs) { for (std::list::const_iterator i = libs.begin(); i != libs.end(); i++) { if (! this->symbolTable.addlibrary(*(*i)->name)) { std::string msg = "Library '" + *(*i)->name + "' not found."; CompileError *err = new CompileError(*(*i), msg); ErrorRegistry::addError(err); } } } void NameLookup::registerUseClauses(const std::list &usecs) { for (std::list::const_iterator i = usecs.begin(); i != usecs.end(); i++) { SimpleName *s = dynamic_cast(*i); if (s == NULL) { // not an expanded name, report an error. CompileError *ce = new CompileError( **i, "Wrong name in use-clause."); ErrorRegistry::addError(ce); return; } //need to resolve to exactly one symbol. if (s->candidates.empty()) { // error was already reported. continue; } // FIXME could be more than one symbols assert(s->candidates.size() == 1); Symbol *sym = s->candidates.front(); // suffix "all" if (*s->name == "all") { assert(sym->region); this->symbolTable.importSymbols(*sym->region); continue; } // FIXME potyra (this goes through to the parser): s.th. l.ike // import x.'y' is also possible, which would be // a character enumeration literal. this->symbolTable.importSymbol(*sym); } } void NameLookup::shiftExpanded(const Symbol &sym) { assert(sym.region != NULL); assert(this->lookupScopes.empty()); this->lookupScopes.push_back(sym.region); this->isExpanded = true; assert(this->shiftedLookups); } std::list NameLookup::shiftSubscriptCands(std::list &cands, Location loc) { std::list result; for (std::list::iterator i = cands.begin(); i != cands.end(); /* nothing */) { Symbol *s = NameLookup::shiftSubscriptCand(*i); if (s == NULL) { // not an array, remove candidate i = cands.erase(i); continue; } result.push_back(s); i++; } if (result.empty()) { CompileError *ce = new CompileError( loc, "Subscript to non-array"); ErrorRegistry::addError(ce); } return result; } Symbol * NameLookup::shiftSubscriptCand(Symbol *candidate) { LookupTypes lt = LookupTypes(true, false); candidate->declaration.accept(lt); const UnconstrainedArrayType *array = dynamic_cast(lt.declaration); if (array == NULL) { return NULL; } TypeDeclaration *et = array->elementType; assert(et != NULL); // FIXME: memory leak (noone will free this symbol) // the return value is a temporary symbol, which points only to the // TypeDeclaration in question and has it's region set. std::string *tn; if (et->name != NULL) { tn = new std::string(*et->name); } else { tn = new std::string("__temporary__"); } Symbol *ret = new Symbol(tn, SYMBOL_TYPE, et->region, // region unneeded *et); return ret; } void NameLookup::shiftSelectedScope(Name &prefix) { /* open scope of type of prefix */ this->isExpanded = false; this->shiftedLookups = true; if (prefix.candidates.empty()) { /* unresolved symbol already reported. */ return; } for (std::list::const_iterator i = prefix.candidates.begin(); i != prefix.candidates.end(); i++) { this->shiftSelectedSym(*i); } } void NameLookup::shiftSelectedSym(Symbol *prefixSym) { LookupTypes lt = LookupTypes(true, false); prefixSym->declaration.accept(lt); if (lt.declaration == NULL) { return; } if (lt.declaration->region == NULL) { return; } this->lookupScopes.push_back(lt.declaration->region); assert(this->shiftedLookups); } /* FIXME for conform*: * according to LRM, 2.7 this check is not enough: * instead, lexical elements (!) have to get compared. */ bool NameLookup::conformProcSig(const Callable* a, const Callable* b) { if ((a == NULL) || (b == NULL)) { return false; } return util::MiscUtil::listMatch(*a->arguments, *b->arguments, NameLookup::conformParameter); } bool NameLookup::conformFuncSig( const FunctionDeclaration* a, const FunctionDeclaration* b ) { if (! NameLookup::conformProcSig(a, b)) { return false; } assert(a->returnType); assert(b->returnType); assert(a->returnType->typeName); assert(a->returnType->typeName->candidates.size() == 1); assert(b->returnType->typeName); assert(b->returnType->typeName->candidates.size() == 1); if ( a->returnType->typeName->candidates.front() != b->returnType->typeName->candidates.front()) { return false; } return true; } bool NameLookup::conformParameter( const ValDeclaration* a, const ValDeclaration* b ) { assert(a); assert(b); if ((*a->name) != (*b->name)) { return false; } if (a->mode != b->mode) { return false; } if (a->storageClass != b->storageClass) { return false; } //compare pointers! assert(a->subtypeIndic); assert(b->subtypeIndic); assert(a->subtypeIndic->typeName); assert(b->subtypeIndic->typeName); assert(a->subtypeIndic->typeName->candidates.size() == 1); assert(b->subtypeIndic->typeName->candidates.size() == 1); if ( a->subtypeIndic->typeName->candidates.front() != b->subtypeIndic->typeName->candidates.front()) { return false; } return true; } }; /* namespace ast */ fauhdlc-20130704/frontend/misc/Driver.hpp0000664000175000017500000000363511137610234017525 0ustar potyrapotyra/* $Id: Driver.hpp 4323 2009-01-27 13:48:12Z potyra $ * Driver: one driver associated to a signal name. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DRIVER_HPP_INCLUDED #define __DRIVER_HPP_INCLUDED #include "frontend/ast/SignalDeclaration.hpp" namespace ast { //! represents one VHDL driver relative to a complete type. /** This can represent one driver of a VHDL signal. It will always reflect * the complete type, i.e. a driver of a composite type is a driver, that * has drivers to each elements embedded. */ class Driver { public: //! c'tor /** @param d corresponding SignalDeclaration. * @param counter unique driver counter. * @param n SimpleName referencing the declaration */ Driver( const SignalDeclaration &d, unsigned int counter, SimpleName *reference); //! d'tor. ~Driver(); //! find out the storage name of the driver /** @return storage name of the driver * FIXME this changes the ABI because it has the number embedded. * (the name of a procedure call's driver would change hence). */ std::string getICName(void) const { return this->signal.getICName() + "__driver__" + util::MiscUtil::toString(this->cnt); } //! find out the foreign name of the driver /** @return foreign name of the driver. */ std::string getForeignName(void) const { return (*this->signal.name) + "__driver__"; } //! corresponding SignalDeclaration const SignalDeclaration &signal; /** SimpleName referring to the declaration */ SimpleName *n; private: /** counter to guarantee that two drivers to the same signal result in * a unique name. */ unsigned int cnt; }; }; /* namespace ast */ #endif /* __DRIVER_HPP_INCLUDED */ fauhdlc-20130704/frontend/misc/BuiltinSymbolTable.cpp0000664000175000017500000006175211307471226022042 0ustar potyrapotyra/* $Id: BuiltinSymbolTable.cpp 4881 2009-12-08 15:36:54Z potyra $ * * BuiltinSymbolTable: SymbolTable preloaded with symbols from std.standard. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #if 1 /* obsolete, use instead. */ /* want INT64_MAX and others defined in c++ */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif /* __STDC_LIMIT_MACROS */ extern "C" { #include "stdint.h" }; #endif #include #include #include #include "frontend/misc/BuiltinSymbolTable.hpp" #include "frontend/ast/Library.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/NodeFactory.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/AttributeDeclaration.hpp" namespace ast { BuiltinSymbolTable::BuiltinSymbolTable() : mayAddStdStandard(false) { this->registerBuiltinSymbols(); this->mayAddStdStandard = true; } void BuiltinSymbolTable::pushNewRegion(void) { SymbolTable::pushNewRegion(); if ((this->regionStack.size() == 2) && this->mayAddStdStandard) { // must be a library unit // add "library std;" this->addlibrary("std"); // and add "using std.standard;" std::list c = this->lookup("std"); assert(c.size() == 1); Symbol *sym = c.front(); assert(sym->type == SYMBOL_LIBRARY); assert(sym->region != NULL); c = sym->region->lookup("standard"); assert(c.size() == 1); sym = c.front(); assert(sym->type == SYMBOL_PACKAGE); assert(sym->region != NULL); this->importSymbols(*sym->region); } } void BuiltinSymbolTable::registerBuiltinSymbols(void) { Library *std = new Library(new std::string("std")); this->pushLibrary(*std); std::list* standardSyms = new std::list(); Package *standard = new Package( new std::string("standard"), NULL, // lib clauses NULL, // use clauses standardSyms, Location("standard")); std->units.push_back(standard); this->registerSymbolWithRegion(SYMBOL_PACKAGE, *standard); this->addStandardStd(*standardSyms); this->popRegion(); /* package standard */ this->popRegion(); /* library std */ this->attributeRegion = new DeclarativeRegion(NULL); assert(this->regionStack.empty()); this->regionStack.push(this->attributeRegion); this->addAttributes(); this->popRegion(); // "__attributes__" } /* helper macros only for adding symbols */ // FIXME maybe templates might be better? or private member functions? /* define an unary operator for the last defined enumeration type. * The operand and the * result type will be the last defined enumeration type. * No different type may get defined in between. */ #define UNOP_ENUM(name, gcBuiltinClass, cpBuiltinClass)\ args = new std::list();\ /* operand */\ subtypeIndic = new SubtypeIndication(et, \ Location("std.standard"));\ c = new ConstantDeclaration(new std::string("__anonymous__"), \ NULL,\ subtypeIndic,\ false,\ Location("std.standard"));\ args->push_back(c);\ /* return type */\ subtypeIndic = new SubtypeIndication(et, \ Location("std.standard"));\ /* create function declaration */\ f = new FunctionDeclaration(new std::string(name),\ args,\ subtypeIndic,\ true,\ Location("std.standard"));\ f->isBuiltin = true; \ f->builtin = new cpBuiltinClass(); \ f->gcBuiltin = new gcBuiltinClass(); \ this->registerSymbol(SYMBOL_FUNCTION, *f);\ standardSyms.push_back(f); /* define a binary operator for the last enumeration defined type. * Both operands and the * result type will be the last defined enumeration type. * No different type may get defined in between. */ #define BINOP_ENUM(name, gcBuiltinClass, cpBuiltinClass)\ args = new std::list();\ /* left operand */\ subtypeIndic = new SubtypeIndication(et, \ Location("std.standard"));\ c = new ConstantDeclaration(new std::string("__anonymous__"), \ NULL,\ subtypeIndic,\ false, \ Location("std.standard"));\ args->push_back(c);\ /* right operand */\ subtypeIndic = new SubtypeIndication(et, \ Location("std.standard"));\ c = new ConstantDeclaration(new std::string("__anonymous__"), \ NULL,\ subtypeIndic,\ false, \ Location("std.standard"));\ args->push_back(c);\ /* return type */\ subtypeIndic = new SubtypeIndication(et, \ Location("std.standard"));\ /* create function declaration */\ f = new FunctionDeclaration(new std::string(name),\ args,\ subtypeIndic,\ true,\ Location("std.standard"));\ f->isBuiltin = true; \ f->builtin = new cpBuiltinClass(); \ f->gcBuiltin = new gcBuiltinClass(); \ this->registerSymbol(SYMBOL_FUNCTION, *f);\ standardSyms.push_back(f); #define RANGE_CONSTRAINT_BINOP(name, left, right, result) \ args = new std::list();\ /* left operand */\ subtypeIndic = new SubtypeIndication(left, \ Location("std.standard"));\ c = new ConstantDeclaration(new std::string("__anonymous__"),\ NULL, \ subtypeIndic, \ false, \ Location("std.standard"));\ args->push_back(c);\ /* right operand */\ subtypeIndic = new SubtypeIndication(right, \ Location("std.standard"));\ c = new ConstantDeclaration(new std::string("__anonymous__"),\ NULL, \ subtypeIndic, \ false, \ Location("std.standard"));\ args->push_back(c);\ /* return type */\ subtypeIndic = new SubtypeIndication(result, \ Location("std.standard"));\ f = new FunctionDeclaration(new std::string(name),\ args, \ subtypeIndic, \ true, \ Location("std.standard"));\ f->isBuiltin = true; \ this->registerSymbol(SYMBOL_FUNCTION, *f);\ standardSyms.push_back(f); /* begin an enumeration type */ #define ENUM_BEGIN(sym) \ s = new std::string(sym);\ enumElems = new std::list(); /* end en enumeration type */ #define ENUM_END \ et = new EnumerationType(s, enumElems, \ Location("std.standard"));\ sym = this->registerSymbol(SYMBOL_TYPE, *et);\ NodeFactory::registerEnumElems(et, *this, sym);\ standardSyms.push_back(et); #define RANGE_CONSTRAINT_INT(name, lower, upper) \ s = new std::string(name);\ i1 = new ConstInteger(lower, Location("lower bound"));\ i2 = new ConstInteger(upper, Location("upper bound"));\ dr = new DiscreteRange(i1, i2, DiscreteRange::DIRECTION_UP, \ Location("constraint"));\ r = new RangeConstraintType(s, dr, Location(name));\ r->baseType = BASE_TYPE_INTEGER;\ \ this->registerSymbol(SYMBOL_TYPE, *r);\ standardSyms.push_back(r); #define RANGE_CONSTRAINT_REAL(name, lower, upper) \ s = new std::string(name);\ r1 = new ConstReal(lower, Location("lower bound"));\ r2 = new ConstReal(upper, Location("upper bound"));\ dr = new DiscreteRange(r1, r2, DiscreteRange::DIRECTION_UP, \ Location("constraint"));\ r = new RangeConstraintType(s, dr, Location(name));\ r->baseType = BASE_TYPE_REAL;\ \ this->registerSymbol(SYMBOL_TYPE, *r);\ standardSyms.push_back(r); /** define a subtype of the *last* defined integer range constraint type */ #define RANGE_CONSTRAINT_SUBTYPE_INT(name1, lower, upper) \ subtypeIndic = new SubtypeIndication(r, Location("std.standard")); \ subtypeIndic->name = new std::string(name1); \ i1 = new ConstInteger(lower, Location("lower bound")); \ i2 = new ConstInteger(upper, Location("upper bound")); \ dr = new DiscreteRange(i1, i2, DiscreteRange::DIRECTION_UP, \ Location("constraint")); \ subtypeIndic->constraint = dr; \ this->registerSymbol(SYMBOL_TYPE, *subtypeIndic); \ standardSyms.push_back(subtypeIndic); #define DEFINELOCALS() \ std::string *s;\ ConstReal *r1;\ ConstReal *r2;\ ConstInteger *i1;\ ConstInteger *i2;\ DiscreteRange *dr;\ RangeConstraintType *r;\ std::list *enumElems;\ EnumerationType *et;\ SubtypeIndication *subtypeIndic;\ ConstantDeclaration *c;\ std::list *args;\ FunctionDeclaration *f;\ Symbol *sym; void BuiltinSymbolTable::addStandardStd( std::list &standardSyms ) { // tricky: each type that gets registered, will create a number // of operations (cf. RegisterBuiltins and LRM 7.2). // Hence the order, in which the types get registered // is important. // As an example, every range constraint type t will define // boolean "=" (t, t). // For this, the type boolean must be defined already. // // Operators, that apply only to specific types, will get // defined here, every generic operator will get defined // via RegisterBuiltins. // // Generic operators will get (automatically) defined *after* // a specific type was registered. That way it is possible to // register the type boolean, since the generic operators of // enumeration types use boolean as a result type. DEFINELOCALS(); // type boolean ENUM_BEGIN("boolean") BuiltinSymbolTable::addEnumStr(*enumElems,"false"); BuiltinSymbolTable::addEnumStr(*enumElems,"true"); ENUM_END BINOP_ENUM("and", GCBuiltinsAnd, EnumAND) BINOP_ENUM("or", GCBuiltinsOr, EnumOR) BINOP_ENUM("nand", GCBuiltinsNand, EnumNAND) BINOP_ENUM("nor", GCBuiltinsNor, EnumNOR) BINOP_ENUM("xor", GCBuiltinsXor, EnumXOR) BINOP_ENUM("xnor", GCBuiltinsXnor, EnumXNOR) UNOP_ENUM("not", GCBuiltinsNot, EnumNOT) //type bit ENUM_BEGIN("bit") BuiltinSymbolTable::addEnumChar(*enumElems,'0'); BuiltinSymbolTable::addEnumChar(*enumElems,'1'); ENUM_END BINOP_ENUM("and", GCBuiltinsAnd, EnumAND) BINOP_ENUM("or", GCBuiltinsOr, EnumOR) BINOP_ENUM("nand", GCBuiltinsNand, EnumNAND) BINOP_ENUM("nor", GCBuiltinsNor, EnumNOR) BINOP_ENUM("xor", GCBuiltinsXor, EnumXOR) BINOP_ENUM("xnor", GCBuiltinsXnor, EnumXNOR) UNOP_ENUM("not", GCBuiltinsNot, EnumNOT) //type character ENUM_BEGIN("character") BuiltinSymbolTable::addEnumStr(*enumElems,"NUL"); // 0 BuiltinSymbolTable::addEnumStr(*enumElems,"SOH"); BuiltinSymbolTable::addEnumStr(*enumElems,"STX"); BuiltinSymbolTable::addEnumStr(*enumElems,"ETX"); BuiltinSymbolTable::addEnumStr(*enumElems,"EOT"); BuiltinSymbolTable::addEnumStr(*enumElems,"ENQ"); BuiltinSymbolTable::addEnumStr(*enumElems,"ACK"); BuiltinSymbolTable::addEnumStr(*enumElems,"BEL"); BuiltinSymbolTable::addEnumStr(*enumElems,"BS"); BuiltinSymbolTable::addEnumStr(*enumElems,"HT"); BuiltinSymbolTable::addEnumStr(*enumElems,"LF"); // 10 BuiltinSymbolTable::addEnumStr(*enumElems,"VT"); BuiltinSymbolTable::addEnumStr(*enumElems,"FF"); BuiltinSymbolTable::addEnumStr(*enumElems,"CR"); BuiltinSymbolTable::addEnumStr(*enumElems,"SO"); BuiltinSymbolTable::addEnumStr(*enumElems,"SI"); BuiltinSymbolTable::addEnumStr(*enumElems,"DLE"); BuiltinSymbolTable::addEnumStr(*enumElems,"DC1"); BuiltinSymbolTable::addEnumStr(*enumElems,"DC2"); BuiltinSymbolTable::addEnumStr(*enumElems,"DC3"); BuiltinSymbolTable::addEnumStr(*enumElems,"DC4"); // 20 BuiltinSymbolTable::addEnumStr(*enumElems,"NAK"); BuiltinSymbolTable::addEnumStr(*enumElems,"SYN"); BuiltinSymbolTable::addEnumStr(*enumElems,"ETB"); BuiltinSymbolTable::addEnumStr(*enumElems,"CAN"); BuiltinSymbolTable::addEnumStr(*enumElems,"EM"); BuiltinSymbolTable::addEnumStr(*enumElems,"SUB"); BuiltinSymbolTable::addEnumStr(*enumElems,"ESC"); BuiltinSymbolTable::addEnumStr(*enumElems,"FSP"); BuiltinSymbolTable::addEnumStr(*enumElems,"GSP"); BuiltinSymbolTable::addEnumStr(*enumElems,"RSP"); // 30 BuiltinSymbolTable::addEnumStr(*enumElems,"USB"); BuiltinSymbolTable::addEnumChar(*enumElems,' '); BuiltinSymbolTable::addEnumChar(*enumElems,'!'); BuiltinSymbolTable::addEnumChar(*enumElems,'"'); BuiltinSymbolTable::addEnumChar(*enumElems,'#'); BuiltinSymbolTable::addEnumChar(*enumElems,'$'); BuiltinSymbolTable::addEnumChar(*enumElems,'%'); BuiltinSymbolTable::addEnumChar(*enumElems,'&'); BuiltinSymbolTable::addEnumChar(*enumElems,'\''); BuiltinSymbolTable::addEnumChar(*enumElems,'('); // 40 BuiltinSymbolTable::addEnumChar(*enumElems,')'); BuiltinSymbolTable::addEnumChar(*enumElems,'*'); BuiltinSymbolTable::addEnumChar(*enumElems,'+'); BuiltinSymbolTable::addEnumChar(*enumElems,','); BuiltinSymbolTable::addEnumChar(*enumElems,'-'); BuiltinSymbolTable::addEnumChar(*enumElems,'.'); BuiltinSymbolTable::addEnumChar(*enumElems,'/'); BuiltinSymbolTable::addEnumChar(*enumElems,'0'); BuiltinSymbolTable::addEnumChar(*enumElems,'1'); BuiltinSymbolTable::addEnumChar(*enumElems,'2'); // 50 BuiltinSymbolTable::addEnumChar(*enumElems,'3'); BuiltinSymbolTable::addEnumChar(*enumElems,'4'); BuiltinSymbolTable::addEnumChar(*enumElems,'5'); BuiltinSymbolTable::addEnumChar(*enumElems,'6'); BuiltinSymbolTable::addEnumChar(*enumElems,'7'); BuiltinSymbolTable::addEnumChar(*enumElems,'8'); BuiltinSymbolTable::addEnumChar(*enumElems,'9'); BuiltinSymbolTable::addEnumChar(*enumElems,':'); BuiltinSymbolTable::addEnumChar(*enumElems,';'); BuiltinSymbolTable::addEnumChar(*enumElems,'<'); // 60 BuiltinSymbolTable::addEnumChar(*enumElems,'='); BuiltinSymbolTable::addEnumChar(*enumElems,'>'); BuiltinSymbolTable::addEnumChar(*enumElems,'?'); BuiltinSymbolTable::addEnumChar(*enumElems,'@'); BuiltinSymbolTable::addEnumChar(*enumElems,'A'); BuiltinSymbolTable::addEnumChar(*enumElems,'B'); BuiltinSymbolTable::addEnumChar(*enumElems,'C'); BuiltinSymbolTable::addEnumChar(*enumElems,'D'); BuiltinSymbolTable::addEnumChar(*enumElems,'E'); BuiltinSymbolTable::addEnumChar(*enumElems,'F'); // 70 BuiltinSymbolTable::addEnumChar(*enumElems,'G'); BuiltinSymbolTable::addEnumChar(*enumElems,'H'); BuiltinSymbolTable::addEnumChar(*enumElems,'I'); BuiltinSymbolTable::addEnumChar(*enumElems,'J'); BuiltinSymbolTable::addEnumChar(*enumElems,'K'); BuiltinSymbolTable::addEnumChar(*enumElems,'L'); BuiltinSymbolTable::addEnumChar(*enumElems,'M'); BuiltinSymbolTable::addEnumChar(*enumElems,'N'); BuiltinSymbolTable::addEnumChar(*enumElems,'O'); BuiltinSymbolTable::addEnumChar(*enumElems,'P'); // 80 BuiltinSymbolTable::addEnumChar(*enumElems,'Q'); BuiltinSymbolTable::addEnumChar(*enumElems,'R'); BuiltinSymbolTable::addEnumChar(*enumElems,'S'); BuiltinSymbolTable::addEnumChar(*enumElems,'T'); BuiltinSymbolTable::addEnumChar(*enumElems,'U'); BuiltinSymbolTable::addEnumChar(*enumElems,'V'); BuiltinSymbolTable::addEnumChar(*enumElems,'W'); BuiltinSymbolTable::addEnumChar(*enumElems,'X'); BuiltinSymbolTable::addEnumChar(*enumElems,'Y'); BuiltinSymbolTable::addEnumChar(*enumElems,'Z'); // 90 BuiltinSymbolTable::addEnumChar(*enumElems,'['); BuiltinSymbolTable::addEnumChar(*enumElems,'\\'); BuiltinSymbolTable::addEnumChar(*enumElems,']'); BuiltinSymbolTable::addEnumChar(*enumElems,'^'); BuiltinSymbolTable::addEnumChar(*enumElems,'_'); BuiltinSymbolTable::addEnumChar(*enumElems,'`'); BuiltinSymbolTable::addEnumChar(*enumElems,'a'); BuiltinSymbolTable::addEnumChar(*enumElems,'b'); BuiltinSymbolTable::addEnumChar(*enumElems,'c'); BuiltinSymbolTable::addEnumChar(*enumElems,'d'); // 100 BuiltinSymbolTable::addEnumChar(*enumElems,'e'); BuiltinSymbolTable::addEnumChar(*enumElems,'f'); BuiltinSymbolTable::addEnumChar(*enumElems,'g'); BuiltinSymbolTable::addEnumChar(*enumElems,'h'); BuiltinSymbolTable::addEnumChar(*enumElems,'i'); BuiltinSymbolTable::addEnumChar(*enumElems,'j'); BuiltinSymbolTable::addEnumChar(*enumElems,'k'); BuiltinSymbolTable::addEnumChar(*enumElems,'l'); BuiltinSymbolTable::addEnumChar(*enumElems,'m'); BuiltinSymbolTable::addEnumChar(*enumElems,'n'); // 110 BuiltinSymbolTable::addEnumChar(*enumElems,'o'); BuiltinSymbolTable::addEnumChar(*enumElems,'p'); BuiltinSymbolTable::addEnumChar(*enumElems,'q'); BuiltinSymbolTable::addEnumChar(*enumElems,'r'); BuiltinSymbolTable::addEnumChar(*enumElems,'s'); BuiltinSymbolTable::addEnumChar(*enumElems,'t'); BuiltinSymbolTable::addEnumChar(*enumElems,'u'); BuiltinSymbolTable::addEnumChar(*enumElems,'v'); BuiltinSymbolTable::addEnumChar(*enumElems,'w'); BuiltinSymbolTable::addEnumChar(*enumElems,'x'); // 120 BuiltinSymbolTable::addEnumChar(*enumElems,'y'); BuiltinSymbolTable::addEnumChar(*enumElems,'z'); BuiltinSymbolTable::addEnumChar(*enumElems,'{'); BuiltinSymbolTable::addEnumChar(*enumElems,'|'); BuiltinSymbolTable::addEnumChar(*enumElems,'}'); BuiltinSymbolTable::addEnumChar(*enumElems,'~'); BuiltinSymbolTable::addEnumStr(*enumElems,"DEL"); BuiltinSymbolTable::addEnumStr(*enumElems,"C128"); BuiltinSymbolTable::addEnumStr(*enumElems,"C129"); BuiltinSymbolTable::addEnumStr(*enumElems,"C130"); // 130 BuiltinSymbolTable::addEnumStr(*enumElems,"C131"); BuiltinSymbolTable::addEnumStr(*enumElems,"C132"); BuiltinSymbolTable::addEnumStr(*enumElems,"C133"); BuiltinSymbolTable::addEnumStr(*enumElems,"C134"); BuiltinSymbolTable::addEnumStr(*enumElems,"C135"); BuiltinSymbolTable::addEnumStr(*enumElems,"C136"); BuiltinSymbolTable::addEnumStr(*enumElems,"C137"); BuiltinSymbolTable::addEnumStr(*enumElems,"C138"); BuiltinSymbolTable::addEnumStr(*enumElems,"C139"); BuiltinSymbolTable::addEnumStr(*enumElems,"C140"); // 140 BuiltinSymbolTable::addEnumStr(*enumElems,"C141"); BuiltinSymbolTable::addEnumStr(*enumElems,"C142"); BuiltinSymbolTable::addEnumStr(*enumElems,"C143"); BuiltinSymbolTable::addEnumStr(*enumElems,"C144"); BuiltinSymbolTable::addEnumStr(*enumElems,"C145"); BuiltinSymbolTable::addEnumStr(*enumElems,"C146"); BuiltinSymbolTable::addEnumStr(*enumElems,"C147"); BuiltinSymbolTable::addEnumStr(*enumElems,"C148"); BuiltinSymbolTable::addEnumStr(*enumElems,"C149"); BuiltinSymbolTable::addEnumStr(*enumElems,"C150"); // 150 BuiltinSymbolTable::addEnumStr(*enumElems,"C151"); BuiltinSymbolTable::addEnumStr(*enumElems,"C152"); BuiltinSymbolTable::addEnumStr(*enumElems,"C153"); BuiltinSymbolTable::addEnumStr(*enumElems,"C154"); BuiltinSymbolTable::addEnumStr(*enumElems,"C155"); BuiltinSymbolTable::addEnumStr(*enumElems,"C156"); BuiltinSymbolTable::addEnumStr(*enumElems,"C157"); BuiltinSymbolTable::addEnumStr(*enumElems,"C158"); BuiltinSymbolTable::addEnumStr(*enumElems,"C159"); // TODO non ascii characters. not supported atm., since scanner // doesn't support these as well. ENUM_END TypeDeclaration *character = et; // severity_level ENUM_BEGIN("severity_level") BuiltinSymbolTable::addEnumStr(*enumElems,"note"); BuiltinSymbolTable::addEnumStr(*enumElems,"warning"); BuiltinSymbolTable::addEnumStr(*enumElems,"error"); BuiltinSymbolTable::addEnumStr(*enumElems,"failure"); ENUM_END // tricky: instead of LRM, integer *must* get defined before // universal_integer, since the exponentation of a // range constraint type has integer as a result type! RANGE_CONSTRAINT_INT("integer", INT64_MIN, INT64_MAX) RANGE_CONSTRAINT_SUBTYPE_INT("natural", 0, INT64_MAX) RANGE_CONSTRAINT_SUBTYPE_INT("positive", 1, INT64_MAX) TypeDeclaration *positive = subtypeIndic; RANGE_CONSTRAINT_INT("__universal_integer__", INT64_MIN, INT64_MAX) TypeDeclaration *universal_integer = r; universal_integer->isUniversal = true; RANGE_CONSTRAINT_REAL("__universal_real__", DBL_MIN, DBL_MAX) TypeDeclaration *universal_real = r; universal_real->isUniversal = true; // additional operations for universal types. RANGE_CONSTRAINT_BINOP("*", universal_real, universal_integer, universal_real); RANGE_CONSTRAINT_BINOP("*", universal_integer, universal_real, universal_real); RANGE_CONSTRAINT_BINOP("/", universal_real, universal_integer, universal_real); RANGE_CONSTRAINT_REAL("real", DBL_MIN, DBL_MAX) this->addStdStandardTime(standardSyms); // FIXME delay_length, now // ... // string std::list *indices = new std::list(); indices->push_back(positive); UnconstrainedArrayType *stringT = new UnconstrainedArrayType(new std::string("string"), indices, character, Location("std.standard")); this->registerSymbol(SYMBOL_TYPE, *stringT); standardSyms.push_back(stringT); // "foreign" attribute this->addForeignAttribute(stringT, standardSyms); } #undef UNOP #undef BINOP_ENUM #undef ENUM_BEGIN #undef ENUM_END #undef RANGE_CONSTRAINT_INT #undef RANGE_CONSTRAINT_REAL #undef RANGE_CONSTRAINT_BINOP #undef DEFINELOCALS void BuiltinSymbolTable::addAttributes(void) { this->addAttributeDecl("event", "boolean"); // TODO } /* FIXME make this a runtime parameter! */ #if 0 /* correct VHDL */ void BuiltinSymbolTable::addStdStandardTime( std::list &standardSyms ) { ConstInteger *i1; ConstInteger *i2; DiscreteRange *dr; std::list *units = new std::list(); #if 0 /* minimum simulation resolution. */ this->addPhysUnit(standardSyms, *units, "ps", 1, NULL); this->addPhysUnit(standardSyms, *units, "ns", 1000, "ps"); #else this->addPhysUnit(standardSyms, *units, "ns", 1, NULL); #endif this->addPhysUnit(standardSyms, *units, "us", 1000, "ns"); this->addPhysUnit(standardSyms, *units, "ms", 1000, "us"); this->addPhysUnit(standardSyms, *units, "sec", 1000, "ms"); this->addPhysUnit(standardSyms, *units, "min", 60, "sec"); this->addPhysUnit(standardSyms, *units, "hr", 60, "min"); i1 = new ConstInteger(INT64_MIN, Location("lower bound")); i2 = new ConstInteger(INT64_MAX, Location("upper bound")); dr = new DiscreteRange(i1, i2, DiscreteRange::DIRECTION_UP, Location("constraint")); PhysicalType *timeT = new PhysicalType( new std::string("time"), dr, units, Location("std.standard")); this->registerSymbol(SYMBOL_TYPE, *timeT); standardSyms.push_back(timeT); } #else /* above: correct VHDL, below: FAUmachine base time */ void BuiltinSymbolTable::addStdStandardTime( std::list &standardSyms ) { ConstInteger *i1; ConstInteger *i2; DiscreteRange *dr; std::list *units = new std::list(); /* minimum simulation unit for FAUmachine is * 1/2^32 sec */ this->addPhysUnit(standardSyms, *units, "__time_hz__", 1, NULL); // ns would be too unsharp (4 vs. ~4.3) this->addPhysUnit(standardSyms, *units, "us", (1ull << 32) / 1000000, "__time_hz__"); this->addPhysUnit(standardSyms, *units, "ms", (1ull << 32) / 1000, "__time_hz__"); this->addPhysUnit(standardSyms, *units, "sec", 1ull << 32, "__time_hz__"); this->addPhysUnit(standardSyms, *units, "min", 60, "sec"); this->addPhysUnit(standardSyms, *units, "hr", 60, "min"); i1 = new ConstInteger(INT64_MIN, Location("lower bound")); i2 = new ConstInteger(INT64_MAX, Location("upper bound")); dr = new DiscreteRange(i1, i2, DiscreteRange::DIRECTION_UP, Location("constraint")); PhysicalType *timeT = new PhysicalType( new std::string("time"), dr, units, Location("std.standard")); this->registerSymbol(SYMBOL_TYPE, *timeT); standardSyms.push_back(timeT); } #endif /* correct VHDL / FAUmachine base unit switch */ void BuiltinSymbolTable::addPhysUnit( std::list &standardSyms, std::list &units, const char *name, universal_integer factor, const char *refName ) { ConstInteger *unit; if (refName == NULL) { unit = new ConstInteger(factor, Location("std.standard")); } else { std::string *s = new std::string(refName); SimpleName *sn = new SimpleName(s, this->lookup(*s), Location("std.stdandard")); unit = new ConstInteger(factor, sn, Location("std.standard")); } PhysicalTypeUnit *pu = new PhysicalTypeUnit( new std::string(name), unit, Location("std.standard")); this->registerSymbol(SYMBOL_UNIT, *pu); units.push_back(pu); standardSyms.push_back(pu); } void BuiltinSymbolTable::addEnumChar( std::list &elems, char c ) { std::string *s = new std::string("'"); s->append(1, c); s->append("'"); FunctionDeclaration *elem = new FunctionDeclaration(s, NULL, NULL, true, Location("std.standard")); elems.push_back(elem); } void BuiltinSymbolTable::addEnumStr( std::list &elems, const char *s ) { std::string *st = new std::string(s); FunctionDeclaration *elem = new FunctionDeclaration(st, NULL, NULL, true, Location("std.standard")); elems.push_back(elem); } void BuiltinSymbolTable::addForeignAttribute( const TypeDeclaration *stringT, std::list &standardSyms ) { AttributeDeclaration *a = new AttributeDeclaration(new std::string("foreign"), stringT, Location("std.standard")); this->registerSymbol(SYMBOL_ATTRIBUTE, *a); standardSyms.push_back(a); } void BuiltinSymbolTable::addAttributeDecl( const char *name, const char *type ) { const TypeDeclaration *t = this->getStdStandardType(type); assert(t != NULL); AttributeDeclaration *a = new AttributeDeclaration( new std::string(name), t, Location("builtin")); this->registerSymbol(SYMBOL_ATTRIBUTE, *a); // FIXME an Attribute should have either an // associated constant builtin function, // an associated inline builtin generator // or both // or a constant value related to it. // // FIXME result types can be variadic! } }; /* namespace ast */ fauhdlc-20130704/frontend/misc/DeclarativeRegion.cpp0000664000175000017500000000746511137610234021661 0ustar potyrapotyra/* $Id: DeclarativeRegion.cpp 4323 2009-01-27 13:48:12Z potyra $ * * DeclarativeRegion: One pocket to store symbols. Can be chained together. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include "frontend/misc/DeclarativeRegion.hpp" #include "frontend/reporting/DuplicateName.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #define DEBUG 0 #define HEAVY_DEBUG 0 namespace ast { DeclarativeRegion::DeclarativeRegion( DeclarativeRegion *p ) : parent(p) { } DeclarativeRegion::~DeclarativeRegion() { for (std::list::const_iterator i = this->declarations.begin(); i != this->declarations.end(); i++) { if ((*i)->region) { delete (*i)->region; } delete *i; } } void DeclarativeRegion::registerSymbol(Symbol *sym) { //check for homographs. const Symbol *dup = this->containsHomograph(*sym); if (dup != NULL) { DuplicateName *dn = new DuplicateName( sym->declaration, dup->declaration, *sym->name); ErrorRegistry::addError(dn); return; } this->declarations.push_back(sym); } const Symbol* DeclarativeRegion::containsHomograph(const Symbol &sym) const { for (std::list::const_iterator i = this->declarations.begin(); i != this->declarations.end(); i++) { if ((*i)->isHomograph(sym)){ return *i; } } return NULL; } bool DeclarativeRegion::isEnclosingSymbol(const Symbol &sym) const { if (sym.region == NULL) { return false; } if (sym.region == this) { return true; } if (this->parent != NULL) { return this->parent->isEnclosingSymbol(sym); } return false; } std::list DeclarativeRegion::lookup(const std::string &name) const { std::list result; #if DEBUG std::cerr << "STARTING LOOKUP for " << name << std::endl; #endif this->lookupRec(name, result); return result; } std::list DeclarativeRegion::lookupLocal(const std::string &name) const { std::list result = std::list(); for (std::list::const_iterator i = this->declarations.begin(); i != this->declarations.end(); i++) { if ((*(*i)->name) == name) { result.push_back(*i); } } return result; } void DeclarativeRegion::lookupRec( const std::string &name, std::list &candidates ) const { // lookup in local region for (std::list::const_iterator i = this->declarations.begin(); i != this->declarations.end(); i++) { #if HEAVY_DEBUG /* causes extreme debug output */ std::cerr << " c>" << (*(*i)->name) << std::endl; #endif /* HEAVY_DEBUG */ if ((*(*i)->name) == name) { // check visibility assert(*i); if (this->isVisible(**i, candidates)) { candidates.push_back(*i); } } } //lookup in imported symbols for (std::list::const_iterator i = this->imports.begin(); i != this->imports.end(); i++) { #if HEAVY_DEBUG /* causes extreme debug output */ std::cerr << " i>" << (*(*i)->name) << std::endl; #endif /* HEAVY_DEBUG */ if ((*(*i)->name) == name) { // check visibility assert(*i); if (this->isVisible(**i, candidates)) { candidates.push_back(*i); } } } // traverse to parent Declarative Region. if (this->parent) { #if 0 /* not useful w.o. above output */ std::cerr << " going up." << std::endl; #endif /* 0 */ this->parent->lookupRec(name, candidates); } } bool DeclarativeRegion::isVisible( const Symbol &sym, const std::list &check ) const { for (std::list::const_iterator i = check.begin(); i != check.end(); i++) { assert(*i); if (sym.isHomograph(**i)) { return false; } } return true; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/0000775000175000017500000000000012165333075016325 5ustar potyrapotyrafauhdlc-20130704/frontend/visitor/GCTypes.cpp0000664000175000017500000002545611305513466020362 0ustar potyrapotyra/* $Id: GCTypes.cpp 4850 2009-12-02 16:35:02Z potyra $ * * Generate intermediate code, related to type handling. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/GCTypes.hpp" #include #include "frontend/ast/RecordType.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/ConstArray.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/reporting/CompileError.hpp" #include "util/MiscUtil.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/operands/IndirectOperand.hpp" #include "intermediate/operands/RegisterFactory.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Je.hpp" #include "intermediate/opcodes/Jne.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Jbe.hpp" #include "intermediate/opcodes/Jmp.hpp" #include "intermediate/opcodes/IMul.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/opcodes/Call.hpp" #include "intermediate/container/Label.hpp" #include "intermediate/container/LabelFactory.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/container/TypeFactory.hpp" #include "intermediate/container/Type.hpp" #include "intermediate/container/TypeElement.hpp" #include "intermediate/container/TypeFactory.hpp" namespace ast { /* import some names into current namespace, just to avoid lengthy types */ using namespace intermediate; universal_integer GCTypes::calcArrayBound( const std::list &indices ) { universal_integer card = 1; for (std::list::const_iterator i = indices.begin(); i != indices.end(); i++) { card *= (*i)->getArraySize(); } if (card < 0) { // null array return 0; } return card; } /* * ================== GENTYPEELEMENTS =============== */ GCTypes::GenTypeElements::GenTypeElements( bool addInitializer, const char *uErrMsg, const AstNode &errNode, const AstNode *constInitExp ) : composite(std::list()), constraint(NULL), addInit(addInitializer), mungeIndices(false), uAErrMsg(uErrMsg), errorNode(errNode), isForeign(false), constInit(constInitExp) { } void GCTypes::GenTypeElements::visit(RangeConstraintType &node) { switch(node.baseType) { case BASE_TYPE_INTEGER: this->processDR(*node.constraint, &node); break; case BASE_TYPE_REAL: this->processDR(*node.constraint, &node); break; default: assert(false); } } template void GCTypes::GenTypeElements::processDR( DiscreteRange &node, TypeDeclaration *actualType ) { std::list initVs = std::list(); ImmediateOperand *init = NULL; if (this->addInit) { const T *iv; if (this->constInit != NULL) { iv = dynamic_cast(this->constInit); } else { assert(node.from != NULL); assert(node.to != NULL); iv = dynamic_cast(node.from); } // FIXME can fail, if not const initializer from if-path assert(iv != NULL); init = new ImmediateOperand(iv->value); initVs.push_back(init); } TypeElement *te = new TypeElement(TypeFactory::getTypeName( actualType->baseType), initVs, this->calcArrayBound()); this->composite.push_back(te); this->referredTypes.push_back(actualType); } void GCTypes::GenTypeElements::visit(EnumerationType &node) { std::list initVs = this->getInitValue(); TypeElement *te = new TypeElement(TypeFactory::getTypeName(BASE_TYPE_INTEGER), initVs, this->calcArrayBound()); this->composite.push_back(te); this->referredTypes.push_back(&node); } void GCTypes::GenTypeElements::visit(SubtypeIndication &node) { switch (node.baseType) { case BASE_TYPE_INTEGER: case BASE_TYPE_ENUM: this->processSI(node); // return early. return; case BASE_TYPE_REAL: this->processSI(node); // return early. return; case BASE_TYPE_ARRAY: this->processSIArray(node); break; case BASE_TYPE_RECORD: // doesn't really make sense imho... but let's traverse to the // base type. (but it is allowed by lrm) break; default: // must not happen assert(false); } TypeDeclaration *t = const_cast(node.declaration); t->accept(*this); } template void GCTypes::GenTypeElements::processSI(SubtypeIndication &node) { if (node.constraint != NULL) { this->processDR(*node.constraint, &node); return; } // no constraint set, traverse to parent TypeDeclaration *fixme = const_cast(node.declaration); fixme->accept(*this); } void GCTypes::GenTypeElements::visit(RecordType &node) { assert(this->indexConstraint.empty() || this->mungeIndices); TypeElement *te = new TypeElement(node.getICName(), std::list(), this->calcArrayBound()); this->composite.push_back(te); this->referredTypes.push_back(&node); } void GCTypes::GenTypeElements::visit(UnconstrainedArrayType &node) { if (this->indexConstraint.empty() && (this->uAErrMsg != NULL)) { CompileError *ce = new CompileError(this->errorNode, this->uAErrMsg); ErrorRegistry::addError(ce); return; } std::string name = ""; assert(node.elementType != NULL); switch (node.elementType->baseType) { case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: case BASE_TYPE_ENUM: node.elementType->accept(*this); return; case BASE_TYPE_RECORD: { name = this->findName(*node.elementType); TypeElement *te = new TypeElement(name, std::list(), this->calcArrayBound()); this->composite.push_back(te); this->referredTypes.push_back(node.elementType); return; } case BASE_TYPE_ARRAY: { bool mibackup = this->mungeIndices; this->mungeIndices = true; node.elementType->accept(*this); this->mungeIndices = mibackup; return; } default: break; } /* not reached */ assert(false); } void GCTypes::GenTypeElements::visit(PhysicalType &node) { assert(node.constraint != NULL); assert(node.baseType == BASE_TYPE_INTEGER); this->processDR(*node.constraint, &node); } void GCTypes::GenTypeElements::processSIArray(SubtypeIndication &node) { if (node.indexConstraint != NULL) { if ((! (this->indexConstraint.empty())) && (! this->mungeIndices)) { // only one index constraint allowed, // lrm 3.2.1.1 std::string msg = std::string("Index " "constraint already defined at "); DiscreteRange *f = this->indexConstraint.front(); msg += util::MiscUtil::toString(f->location); CompileError *ce = new CompileError(node, msg); ErrorRegistry::addError(ce); return; } // munge indices together this->indexConstraint.insert(this->indexConstraint.end(), node.indexConstraint->begin(), node.indexConstraint->end()); this->mungeIndices = false; } } void GCTypes::GenTypeElements::reset(void) { // FIXME what about other member? (e.g. mungeIndices) this->indexConstraint.clear(); this->constraint = NULL; } std::list GCTypes::GenTypeElements::getIndices(void) const { return this->indexConstraint; } std::string GCTypes::GenTypeElements::findName(const TypeDeclaration &node) { // make sure it's an array or record switch (node.baseType) { case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: break; default: assert(false); } if (node.name != NULL) { assert(! node.pathName.empty()); return node.getICName(); } // unnamed, so assume that it is a SubtypeIndication const SubtypeIndication *si = dynamic_cast(&node); if (si == NULL) { // FIXME possible that it is an anonymous type? assert(false); } return GCTypes::GenTypeElements::findName(*(si->declaration)); } std::list GCTypes::GenTypeElements::getInitValue(void) const { std::list initVs = std::list(); if (! this->addInit) { return initVs; } if (this->constInit == NULL) { // FIXME why does this happen? return initVs; } const ConstInteger *ci = dynamic_cast(this->constInit); if (ci != NULL) { initVs.push_back(new ImmediateOperand(ci->value)); return initVs; } const ConstArray *ca = dynamic_cast(this->constInit); if (ca != NULL) { assert(ca->elements != NULL); for (std::vector::const_iterator i = ca->elements->begin(); i != ca->elements->end(); i++) { initVs.push_back(new ImmediateOperand((*i)->value)); } return initVs; } //FIXME ConstReal assert(false); } universal_integer GCTypes::GenTypeElements::calcArrayBound(void) const { return GCTypes::calcArrayBound(this->indexConstraint); } /* * ===================== GENTYPES ================= */ void GCTypes::GenTypes::visit(EnumerationType &node) { // not a composite, don't create type for this one. } void GCTypes::GenTypes::visit(RangeConstraintType &node) { // not a composite, don't create type for this one. } void GCTypes::GenTypes::visit(PhysicalType &node) { // not a composite, don't create type for this one. } void GCTypes::GenTypes::visit(RecordType &node) { assert(node.elements != NULL); assert(node.name != NULL); GenTypeElements gte = GenTypeElements(false, "Unconstraint array not allowed in a " "record type", node, NULL); for (std::list::iterator i = node.elements->begin(); i != node.elements->end(); i++) { assert((*i)->subtype != NULL); (*i)->subtype->accept(gte); gte.reset(); } this->type = TypeFactory::getType(node.getICName(), gte.composite); } void GCTypes::GenTypes::visit(UnconstrainedArrayType &node) { // do nothing for unconstraint arrays, as these can never // result in a intermediate code type. } void GCTypes::GenTypes::visit(SubtypeIndication &node) { if (node.name == NULL) { // must not be an anonymous type! assert(false); return; } switch (node.baseType) { case BASE_TYPE_RECORD: // FIXME this is allowed by LRM! assert(false); return; case BASE_TYPE_ARRAY: break; default: // not composite -> do nothing. // (non-composite types don't need to be reflected // in the intermediate code, as these will always // be represented with universal_integer/universal_real) return; } // composite type GenTypeElements gte = GenTypeElements(false, "Unconstraint array not allowed in a " "composite type", node, NULL); node.accept(gte); this->type = TypeFactory::getType(node.getICName(), gte.composite); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/NormalizeAssocLists.hpp0000664000175000017500000001342511207763557023023 0ustar potyrapotyra/* $Id: NormalizeAssocLists.hpp 4520 2009-05-29 13:47:27Z potyra $ * * Normalize association lists. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NORMALIZE_ASSOC_LISTS_HPP_INCLUDED #define __NORMALIZE_ASSOC_LISTS_HPP_INCLUDED #include "frontend/visitor/NullVisitor.hpp" #include #include "frontend/ast/Location.hpp" #include "frontend/misc/DeclarativeRegion.hpp" #include "frontend/ast/ValDeclaration.hpp" namespace ast { //! normalize association lists. /** This class will reorder association lists into the corresponding * order of the defining port-/parameter-list. * FIXME: what to do with composites? and conversion functions? * FIXME: */ class NormalizeAssocLists : public NullVisitor { public: //! c'tor: initialize members. NormalizeAssocLists( ) : pickedUpVal(NULL), pos(-1), positional(true), region(NULL), arch(NULL), hiddenCounter(0) {} private: /** Visit a CompInstStat node. * @param node CompInstStat node that get's visited. */ virtual void visit(CompInstStat& node); /** Visit a AssociationElement node. * @param node AssociationElement node that get's visited. */ virtual void visit(AssociationElement& node); /** visit a SimpleName * @param node node that get's visited. */ virtual void visit(SimpleName &node); /** visit a TemporaryName * @param node node that get's visited. */ virtual void visit(TemporaryName &node); /** visit a SelectedName * @param node node that get's visited. */ virtual void visit(SelectedName &node); /** visit a AttributeName * @param node node that get's visited. */ virtual void visit(AttributeName &node); /** Visit a Architecture node. * * @param node Architecture node that get's visited. */ virtual void visit(Architecture& node); /** Visit a Library node. * @param node Library node that get's visited. */ virtual void visit(Library &node); /** Visit a LibraryList node. * @param node LibraryList node that get's visited. */ virtual void visit(LibraryList &node); /** find val in formals and return the position. Also remove it from * from formals and report an error in case val is not in formals. * @param val ValDeclaration to find/delete in current formals list * @param loc error location for error reporting. * @return position number or -1 on error. */ int findAndRemove(const ValDeclaration *val, Location errLoc); /** add associations for unassociated ports of a CompInstStat. * Reports errors. * @param node instantiation statement. */ void addMissingPortAssocs(CompInstStat &node); /** add associations for unassociated generics of a CompInstStat. * Reports errors. * @param node instantiation statement. */ void addMissingGenericAssocs(CompInstStat &node); /** add associations for unassociated ports/generics of a * CompInstStat. * Reports errors. * @param node instantiation statement. * @param unassociated list of unassociated elements. * @param kind element kind (for error reporting) * @param symbolType type of symbol when registering hidden symbols. * @param mapList list of map aspect (generic map, port map). */ template void addMissingAssocs( CompInstStat &node, std::list &unassociated, const char *kind, enum symType symbolType, std::list &mapList); /** add one missing association. To be called by addMissingPortAssocs. * Reports errors. * @param loc location for error reporting. * @param formal declaration of the corresponding formal of an open * association. * @param kind element kind (for reporting errors). * @param symbolType type of symbol when registering hidden symbols. * @param mapList list of map aspect (generic map, port map). */ template void addMissingAssoc( const Location &loc, ValDeclaration &formal, const char *kind, enum symType symbolType, std::list &mapList); template static T *createVal( std::string *name, enum ValDeclaration::Mode pMode, Expression *varInit, SubtypeIndication *si, Location loc); public: /* FIXME used in GenCode as well, move somewhere where it makes * more sense! */ /** make a simple name referring to ValDeclaration val which resides * in the declarative region lookupRegion. * @param val ValDeclaration that should be referred to. * @param lookupRegion region in which val is declared. * @param loc Location of the generated name. * @return SimpleName referring to val or NULL on error. */ static SimpleName * makeNameOfVal( const ValDeclaration *val, const DeclarativeRegion *lookupRegion, Location loc); private: /** current list of formals (ports, generics). * Consumed ports/generics will be removed. */ std::list formals; /** when traversing to a named association, the picked up * declaration lands here */ const ValDeclaration *pickedUpVal; /** current position of the first element of ports. */ int pos; /** positional association used so far? */ bool positional; /** region of the entity to lookup ports */ const DeclarativeRegion *region; /** surrounding Architecture of a CompInstStat (or NULL) */ const Architecture *arch; /** counter so that hidden signals have a unique name */ int hiddenCounter; /** order predicate used for sorting port maps by position */ static bool sortPosPred(AssociationElement *l, AssociationElement *r); }; }; /* namespace ast */ #endif /* __NORMALIZE_ASSOC_LISTS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GCArrays.cpp0000664000175000017500000002552611245452566020523 0ustar potyrapotyra/* $Id: GCArrays.cpp 4610 2009-08-27 09:44:22Z potyra $ * * Generate intermediate code, array specific parts. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/GCArrays.hpp" #include #include "frontend/visitor/GenCode.hpp" #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/visitor/GCTypes.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "intermediate/operands/RegisterFactory.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/operands/IndirectOperand.hpp" #include "intermediate/container/LabelFactory.hpp" #include "intermediate/container/TypeFactory.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Je.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Jbe.hpp" #include "intermediate/opcodes/Jmp.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/opcodes/IMul.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/AOffset.hpp" namespace ast { using namespace intermediate; /* * ===================== ARRAY HANDLING ======================= */ ArrayHandling::ArrayHandling( TypeDeclaration *at, Operand *b, CodeContainer &container, std::list lbounds, std::list rbounds, std::list directs ) : arrayType(at), base(b), cc(container), leftBounds(lbounds), rightBounds(rbounds), directions(directs) { assert(at != NULL); assert(at->baseType == BASE_TYPE_ARRAY); GCTypes::GenTypeElements gte = GCTypes::GenTypeElements(false, NULL, *this->arrayType, NULL); this->arrayType->accept(gte); this->indices = gte.getIndices(); for (std::list::const_iterator i = this->indices.begin(); i != this->indices.end(); i++) { ImmediateOperand *lb = new ImmediateOperand((*i)->getLeftBound()); ImmediateOperand *rb = new ImmediateOperand((*i)->getRightBound()); ImmediateOperand *direct = new ImmediateOperand((*i)->getDirection()); this->leftBounds.push_back(lb); this->rightBounds.push_back(rb); this->directions.push_back(direct); } assert(gte.composite.size() == 1); assert(gte.referredTypes.size() == 1); TypeElement *elem = gte.composite.front(); std::string name = elem->name; this->itype = TypeFactory::lookupType(name); assert(this->itype != NULL); this->elementType = gte.referredTypes.front(); } ArrayHandling::~ArrayHandling() { } void ArrayHandling::factorize(void) { // reverse dimension sizes // (..., d6, d5, d4, d3, d2) std::list rsizes; assert(this->leftBounds.size() == this->rightBounds.size()); assert(this->leftBounds.size() > 0); std::list::const_reverse_iterator lbit = this->leftBounds.rbegin(); std::list::const_reverse_iterator rbit = this->rightBounds.rbegin(); std::list::const_reverse_iterator dirit = this->directions.rbegin(); std::list::const_reverse_iterator llast = this->leftBounds.rend(); llast--; // iterate over all but *first* entry (first is the actual dimension // that gets subscribed to with the first subscription element, // so the factor is always constant 1) for (; lbit != llast; lbit++, rbit++, dirit++) { // size := [(right - left) * direction] + 1 Register *r1 = this->cc.createRegister(OP_TYPE_INTEGER); Sub *diff = new Sub(*rbit, *lbit, r1); this->cc.addCode(diff); Register *r2 = this->cc.createRegister(OP_TYPE_INTEGER); Register *r3 = this->cc.createRegister(OP_TYPE_INTEGER); IMul *m = new IMul(r1, *dirit, r2); Add *inc = new Add(r2, ImmediateOperand::getOne(), r3); this->cc.addCode(m); this->cc.addCode(inc); rsizes.push_back(r3); } // factors should be // (d2 * d3 * d4 * d5 * d6) // (d3 * d4 * d5 * d6) // (d4 * d5 * d6) // (d5 * d6) // (d6) intermediate::Operand *factorial = ImmediateOperand::getOne(); for (std::list::const_iterator i = rsizes.begin(); i != rsizes.end(); i++) { Register *r1 = this->cc.createRegister(OP_TYPE_INTEGER); IMul *m = new IMul(factorial, *i, r1); this->cc.addCode(m); factorial = r1; this->dimensionFactors.push_front(factorial); } // also store 1 as factor for first dimension this->dimensionFactors.push_front(ImmediateOperand::getOne()); } Register * ArrayHandling::subscribe(std::list relativeIndices) { // array(x, y, z) // corresponds to (d1, d2, d3, d4, d5, d6) // // --> (x - left(d1)) * direction1 * factor(d2, d3, d4, d5, d6) // + (y - left(d2)) * direction2 * factor(d3, d4, d5, d6) // + (y - left(d3)) * direction3 * factor(d4, d5, d6) // // the corresponding factors should be in dimensionFactors // or can be created with factorize(). // if (this->dimensionFactors.empty()) { this->factorize(); } assert(! this->dimensionFactors.empty()); assert(this->dimensionFactors.size() >= relativeIndices.size()); assert(this->itype != NULL); Operand *offset = ImmediateOperand::getZero(); std::list::const_iterator f = this->dimensionFactors.begin(); std::list::const_iterator lb = this->leftBounds.begin(); std::list::const_iterator dir = this->directions.begin(); std::list::const_iterator ri = relativeIndices.begin(); while (ri != relativeIndices.end()) { Register *r1 = this->cc.createRegister(OP_TYPE_INTEGER); Register *r2 = this->cc.createRegister(OP_TYPE_INTEGER); Register *r3 = this->cc.createRegister(OP_TYPE_INTEGER); Register *r4 = this->cc.createRegister(OP_TYPE_INTEGER); Sub *s1 = new Sub(*ri, *lb, r1); IMul *m1 = new IMul(r1, *f, r2); IMul *m2 = new IMul(r2, *dir, r3); Add *a1 = new Add(r3, offset, r4); offset = r4; this->cc.addCode(s1); this->cc.addCode(m1); this->cc.addCode(m2); this->cc.addCode(a1); f++; lb++; ri++; dir++; } Register *result = this->cc.createRegister(OP_TYPE_POINTER); AOffset *ao = new AOffset(this->base, offset, this->itype, result); this->cc.addCode(ao); return result; } universal_integer ArrayHandling::transform_idx( const TypeDeclaration *arrayType, universal_integer idx ) { std::list idcs; ResolveTypes::pickupIndexConstraint(arrayType, idcs); assert(idcs.size() == 1); DiscreteRange *dr = idcs.front(); universal_integer ret = (idx - dr->getLeftBound()) * dr->getDirection(); return ret; } /* * =================== STATIC ARRAY ITERATE =================== */ void StaticArrayIterate::iterate(void) { std::list lbounds = std::list(); std::list rbounds = std::list(); std::list ds = std::list(); std::list i = std::list(); std::list offsetL = std::list(); for (std::list::const_iterator d = this->indices.begin(); d != this->indices.end(); d++) { universal_integer lb = (*d)->getLeftBound(); universal_integer rb = (*d)->getRightBound(); universal_integer dir = (*d)->getDirection(); lbounds.push_back(lb); i.push_back(lb); rbounds.push_back(rb); ds.push_back(dir); } while (StaticArrayIterate::checkLoop(i, rbounds, ds)) { for (std::list::const_iterator i1 = i.begin(); i1 != i.end(); i1++) { offsetL.push_back(new ImmediateOperand(*i1)); } Register *element = this->subscribe(offsetL); this->iterateBody(element, i); StaticArrayIterate::incCounters(i, lbounds, rbounds, ds); offsetL.clear(); } } bool StaticArrayIterate::checkLoop( const std::list &counters, const std::list &rbounds, const std::list &directions ) { std::list::const_iterator i = counters.begin(); std::list::const_iterator j = rbounds.begin(); std::list::const_iterator d = directions.begin(); while (i != counters.end()) { bool ret = (((*i) * (*d)) <= ((*j) * (*d))); if (! ret) { return false; } i++; j++; } return true; } void StaticArrayIterate::incCounters( std::list &counters, const std::list &lbounds, const std::list &rbounds, const std::list &directions ) { bool carry = false; std::list::iterator i = counters.begin(); std::list::const_iterator l = lbounds.begin(); std::list::const_iterator r = rbounds.begin(); std::list::const_iterator d = directions.begin(); (*i) += (*d); while (i != counters.end()) { if (carry) { (*i) += (*d); carry = false; } if (((*r) * (*d)) < ((*i) * (*d))) { carry = true; (*i) = (*l); } i++; r++; l++; d++; } // make sure, that at least one index overflows if all // values have been handled, otherwise checkLoop would // never yield false. if (carry) { i = counters.begin(); r = rbounds.begin(); d = directions.begin(); (*i) = (*r) + (*d); } } /* * =================== ARRAY ITERATE =================== */ void ArrayIterate::initCounters(void) { for (std::list::const_iterator i = this->leftBounds.begin(); i != this->leftBounds.end(); i++) { Register *b = this->cc.createRegister(OP_TYPE_INTEGER); Mov *m = new Mov(*i, b); this->cc.addCode(m); this->counters.push_back(b); } } void ArrayIterate::incCounters(void) { std::list::const_reverse_iterator rbi = this->rightBounds.rbegin(); std::list::const_reverse_iterator lbi = this->leftBounds.rbegin(); std::list::const_reverse_iterator di = this->directions.rbegin(); for (std::list::reverse_iterator i = this->counters.rbegin(); i != this->counters.rend(); i++) { // c = c + direction Add *a = new Add(*di, *i, *i); this->cc.addCode(a); Register *r1 = this->cc.createRegister(OP_TYPE_INTEGER); Register *r2 = this->cc.createRegister(OP_TYPE_INTEGER); // r1 = c * direction // r2 = rightBound * direction IMul *m1 = new IMul(*i, *di, r1); IMul *m2 = new IMul(*rbi, *di, r2); this->cc.addCode(m1); this->cc.addCode(m2); // if r1 <= r2 goto loop Jbe *jbe = new Jbe(r1, r2, this->loop); this->cc.addCode(jbe); // c = lowerBound. Mov *m = new Mov(*lbi, *i); this->cc.addCode(m); rbi++; lbi++; di++; } // we're done with the iteration. } void ArrayIterate::iterate(void) { this->initCounters(); this->cc.addCode(this->loop); std::list idx; for (std::list::iterator i = this->counters.begin(); i != this->counters.end(); i++) { idx.push_back(*i); } Register *elem = this->subscribe(idx); this->iterateBody(elem, this->counters); this->incCounters(); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/CheckLoops.hpp0000664000175000017500000000436411137610234021070 0ustar potyrapotyra/* $Id: CheckLoops.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Check, if next statements occur within a loop statement. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CHECK_LOOPS_HPP_INCLUDED #define __CHECK_LOOPS_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" #include namespace ast { //! check loop statements. /** This class will check, if next statements will occur within loop * statements. * TODO check if loop statements have an effect in the first place. */ class CheckLoops : public TopDownVisitor { private: /** visit a node which affects a loop (Exit statement or * Next statement). * @param node exit or next statement node. * @param kind textual represention of node kind that is checked. */ template void visitLoopCFNode(T &node, const char *kind) const; /** Visit a ExitStat * @param node ExitStat node that get's visited. */ virtual void visit(ExitStat &node); /** Visit a NextStat * @param node NextStat node that get's visited. */ virtual void visit(NextStat &node); //! Process a generic LoopStat. /** This function will get called for each LoopStat (or class * derived from LoopStat) that get's visited. * * @param node LoopStat instance. */ virtual void process(LoopStat &node); //! search the stack for the loop label and return it. /** @param label look for loop statement with given label (optional) * @return corresponding loop statement or NULL if not found. */ LoopStat *lookup(SimpleName *label) const; //! report an error that no corresponding loop was found. /** @param node incorrect node (e.g. next statement). * @param label optional referred to loop label. * @param kind textual representation of kind of loop statement. */ void missingLoop( const AstNode &node, const SimpleName *label, const char *kind) const; //! stack of current loop statements. std::list loops; }; }; /* namespace ast */ #endif /* __CHECK_LOOPS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/CheckAccessMode.cpp0000664000175000017500000002156211164417164022003 0ustar potyrapotyra/* $Id: CheckAccessMode.cpp 4454 2009-03-31 13:45:24Z potyra $ * CheckAccessMode: visitor to check if reading/writing data is permitted * via in,inout,out access modes. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/CheckAccessMode.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/ConstArray.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/reporting/ErrorRegistry.hpp" namespace ast { void CheckAccessMode::visit(SimpleName &node) { assert(node.candidates.size() >= 1); const Symbol *sym = node.candidates.front(); switch (sym->type) { case SYMBOL_SIGNAL: case SYMBOL_PARAMETER: case SYMBOL_VARIABLE: case SYMBOL_PORT: break; default: // skip non variables/signals/parameters return; } ValDeclaration *decl = dynamic_cast( node.getDeclaration()); std::string *action = NULL; std::string *mode_s = NULL; if (this->isForeign) { decl->usage |= ValDeclaration::USAGE_FOREIGN; } switch (this->accessMode) { case ValDeclaration::MODE_IN: if (! this->isForeign) { decl->usage |= ValDeclaration::USAGE_READ; } switch (decl->mode) { case ValDeclaration::MODE_IN: case ValDeclaration::MODE_INOUT: // ok break; case ValDeclaration::MODE_OUT: // error action = new std::string("read from"); mode_s = new std::string("OUT"); break; } break; case ValDeclaration::MODE_OUT: if (! this->isForeign) { decl->usage |= ValDeclaration::USAGE_WRITE; } switch (decl->mode) { case ValDeclaration::MODE_OUT: case ValDeclaration::MODE_INOUT: // ok break; case ValDeclaration::MODE_IN: action = new std::string("write to"); mode_s = new std::string("IN"); break; } break; case ValDeclaration::MODE_INOUT: if (! this->isForeign) { decl->usage |= ValDeclaration::USAGE_READ | ValDeclaration::USAGE_WRITE; } switch (decl->mode) { case ValDeclaration::MODE_INOUT: // ok break; case ValDeclaration::MODE_IN: // error action = new std::string("use as INOUT"); mode_s = new std::string("IN"); break; case ValDeclaration::MODE_OUT: // error action = new std::string("use as INOUT"); mode_s = new std::string("OUT"); break; } break; } if (action == NULL) { return; } std::string msg = std::string("Trying to "); msg += *action; msg += " '"; msg += util::MiscUtil::toString(node); msg += "' which is of mode "; msg += *mode_s; msg += "."; delete action; delete mode_s; CompileError *ce = new CompileError(node, msg); ErrorRegistry::addError(ce); } void CheckAccessMode::visit(VarAssignStat &node) { assert(node.source != NULL); assert(node.target != NULL); this->accessMode = ValDeclaration::MODE_OUT; node.target->accept(*this); this->accessMode = ValDeclaration::MODE_IN; node.source->accept(*this); } void CheckAccessMode::visit(SigAssignStat &node) { assert(node.target != NULL); assert(node.waveForm != NULL); this->accessMode = ValDeclaration::MODE_OUT; node.target->accept(*this); this->accessMode = ValDeclaration::MODE_IN; this->listTraverse(*node.waveForm); } void CheckAccessMode::visit(Subscript &node) { assert(node.indices != NULL); assert(node.source != NULL); enum ValDeclaration::Mode backup = this->accessMode; bool ifc = this->isForeign; this->isForeign = false; this->accessMode = ValDeclaration::MODE_IN; this->listTraverse(*node.indices); this->accessMode = backup; this->isForeign = ifc; node.source->accept(*this); } void CheckAccessMode::visit(Slice &node) { assert(node.source != NULL); assert(node.range != NULL); bool ifc = this->isForeign; this->isForeign = false; enum ValDeclaration::Mode backup = this->accessMode; this->accessMode = ValDeclaration::MODE_IN; node.range->accept(*this); this->isForeign = ifc; this->accessMode = backup; node.source->accept(*this); } void CheckAccessMode::visit(Aggregate &node) { enum ValDeclaration::Mode backup = this->accessMode; bool ifc = this->isForeign; assert(node.associations != NULL); for (std::list::iterator i = node.associations->begin(); i != node.associations->end(); i++) { if ((*i)->choices != NULL) { this->isForeign = false; this->accessMode = ValDeclaration::MODE_IN; this->listTraverse(*(*i)->choices); this->accessMode = backup; this->isForeign = ifc; } if ((*i)->actual != NULL) { (*i)->actual->accept(*this); } } } void CheckAccessMode::visit(ConstInteger &node) { this->processConst(node); } void CheckAccessMode::visit(ConstReal &node) { this->processConst(node); } void CheckAccessMode::visit(ConstArray &node) { this->processConst(node); } void CheckAccessMode::processConst(const Expression &node) const { switch (this->accessMode) { case ValDeclaration::MODE_IN: // ok return; case ValDeclaration::MODE_INOUT: case ValDeclaration::MODE_OUT: // error break; } // error case. CompileError *ce = new CompileError(node, "Trying to access constant expression " "with OUT/INOUT mode."); ErrorRegistry::addError(ce); } void CheckAccessMode::visit(FunctionCall &node) { assert(node.definition != NULL); if (node.arguments != NULL) { this->processCall(*node.arguments, *node.definition); } switch (this->accessMode) { case ValDeclaration::MODE_IN: /* ok */ return; case ValDeclaration::MODE_INOUT: case ValDeclaration::MODE_OUT: // error (return is a value, and must not be written to break; } CompileError *ce = new CompileError(node, "Trying to access the return value of " " a function call via OUT/INOUT."); ErrorRegistry::addError(ce); } void CheckAccessMode::visit(ProcCallStat &node) { assert(node.definition != NULL); if (node.arguments != NULL) { this->processCall(*node.arguments, *node.definition); } } void CheckAccessMode::processCall( std::list &args, const Callable &node ) { bool ifc = this->isForeign; AttributeSpecification *spec = node.hasAttr("foreign"); if (spec != NULL) { this->isForeign = true; } else { this->isForeign = false; } assert(node.arguments != NULL); enum ValDeclaration::Mode backup = this->accessMode; std::list::const_iterator a = node.arguments->begin(); for (std::list::iterator i = args.begin(); i != args.end(); i++, a++) { assert(a != node.arguments->end()); // FIXME handle formals assert((*i)->formal == NULL); assert((*i)->actual != NULL); // FIXME open assocs! this->accessMode = (*a)->mode; (*i)->actual->accept(*this); } this->accessMode = backup; this->isForeign = ifc; } void CheckAccessMode::visit(CompInstStat &node) { assert(node.entity != NULL); // FIXME generic map if (node.portMap != NULL) { for (std::list::iterator i = node.portMap->begin(); i != node.portMap->end(); i++) { assert((*i)->formal != NULL); ValDeclaration *port = dynamic_cast( (*i)->formal->getDeclaration()); // also propagate info from inside to outside. // it's not necessary to propagate this info *back* // to the inside of other entities on the same nesting // level, since it doesn't affect these. if ((port->usage & ValDeclaration::USAGE_FOREIGN) != 0) { this->isForeign = true; } this->accessMode = port->mode; if ((*i)->actual != NULL) { (*i)->actual->accept(*this); } else { assert((*i)->hiddenFormal != NULL); (*i)->hiddenFormal->accept(*this); } this->isForeign = false; } } this->accessMode = ValDeclaration::MODE_IN; this->isForeign = false; } void CheckAccessMode::visit(Entity &node) { AttributeSpecification *spec = node.hasAttr("foreign"); if (spec != NULL) { assert(node.ports != NULL); for (std::list::iterator i = node.ports->begin(); i != node.ports->end(); i++) { (*i)->usage |= ValDeclaration::USAGE_FOREIGN; } } TopDownVisitor::visit(node); } void CheckAccessMode::process(Callable &node) { AttributeSpecification *spec = node.hasAttr("foreign"); // arguments of foreign subprograms always have foreign usage if (spec != NULL) { if (node.arguments != NULL) { for (std::list::const_iterator i = node.arguments->begin(); i != node.arguments->end(); i++) { (*i)->usage = ValDeclaration::USAGE_FOREIGN; } } } TopDownVisitor::process(node); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/UnconstraintBounds.cpp0000664000175000017500000000775311245776177022723 0ustar potyrapotyra/* $Id: UnconstraintBounds.cpp 4620 2009-08-28 15:49:19Z potyra $ * * Resolve ranges of positional and named aggregates, where the type * is an unconstraint array. * * Copyright (C) 2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #if 1 /* that is obsolete... use instead. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif /* __STDC_LIMIT_MACROS */ extern "C" { #include "stdint.h" }; #endif #include "frontend/visitor/UnconstraintBounds.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/visitor/ConstantPropagation.hpp" #include "frontend/visitor/ResolveTypes.hpp" namespace ast { UnconstraintBounds::UnconstraintBounds() : bounds(NULL), low(INT64_MAX), high(INT64_MIN), numElements(0), positional(true) { } void UnconstraintBounds::visit(Aggregate &node) { // first fold constants (to reduce locally static expressions // in choices) #if 0 /* FIXME */ ConstantPropagation cp; node.accept(cp); #endif assert(node.associations != NULL); this->listTraverse(*node.associations); if (this->positional) { // lrm 7.3.2.2: need to determine bounds // by base type. std::list drl; const UnconstrainedArrayType *ua = ResolveTypes::pickupIndexConstraint(node.type, drl); // constraint mustn't be set yet by type. assert(drl.empty()); DiscreteRange *dr = UnconstraintBounds::findIndexRange(ua); // FIXME downto... switch (dr->direction) { case DiscreteRange::DIRECTION_DOWN: assert(false); break; default: break; } this->low = dr->getLowerBound(); this->high = this->low - 1 + this->numElements; // check for overflow of NULL array if (this->numElements == 0) { assert(this->high < this->low); } } ConstInteger *lowBound = new ConstInteger(this->low, node.location); ConstInteger *upBound = new ConstInteger(this->high, node.location); this->bounds = new DiscreteRange( lowBound, upBound, DiscreteRange::DIRECTION_UP, node.location); } void UnconstraintBounds::visit(ElementAssociation &node) { if (node.choices != NULL) { // named association this->positional = false; this->listTraverse(*node.choices); } else { this->numElements++; } } void UnconstraintBounds::visit(Others &node) { //TODO register error assert(false); } void UnconstraintBounds::visit(ConstInteger &node) { // must have come from a formal choice. if (node.value < this->low) { this->low = node.value; } if (this->high < node.value) { this->high = node.value; } } void UnconstraintBounds::visit(DiscreteRange &node) { assert(node.from != NULL); assert(node.to != NULL); node.from->accept(*this); node.to->accept(*this); } void UnconstraintBounds::process(AstNode &node) { // FIXME register error? or is it a logic error? assert(false); } DiscreteRange * UnconstraintBounds::findIndexRange(const UnconstrainedArrayType *at) { // FIXME specification not yet clear to me about // multidimensional arrays... ignore for now. assert(at->indexTypes->size() == 1); const TypeDeclaration *it = at->indexTypes->front(); assert(it != NULL); /* try to determine constraint from SubtypeIndication */ const SubtypeIndication *sit = dynamic_cast(it); while (sit->constraint == NULL) { const SubtypeIndication *sit2 = dynamic_cast( sit->declaration); if (sit2 == NULL) { break; } sit = sit2; } if (sit->constraint != NULL) { return sit->constraint; } // not a subtype const RangeConstraintType *rt = dynamic_cast(sit->declaration); assert(rt != NULL); assert(rt->constraint != NULL); return rt->constraint; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/TransformSigAssign.cpp0000664000175000017500000000500011254460763022612 0ustar potyrapotyra/* $Id: TransformSigAssign.cpp 4676 2009-09-17 16:21:07Z potyra $ * * Transform concurrent signal assignment statements into equivalent * processes. * * Copyright (C) 2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include "frontend/visitor/TransformSigAssign.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/CondalSigAssign.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/NodeFactory.hpp" namespace ast { void TransformSigAssign::visit(Architecture &node) { if (node.concurrentStats == NULL) { return; } this->workList = node.concurrentStats; this->listTraverse(*node.concurrentStats, this->deleteFlag); this->workList = NULL; } void TransformSigAssign::visit(CondalSigAssign &node) { assert(this->workList != NULL); assert(node.assignStat != NULL); this->pickupSignals = true; node.assignStat->accept(*this); // generate proces... std::list *sl = new std::list(); sl->insert(sl->end(), this->sensitivities.begin(), this->sensitivities.end()); WaitStat *ws = new WaitStat( sl, NULL, NULL, node.location); std::list *transformed = new std::list(); transformed->push_back(node.assignStat); transformed->push_back(ws); Process *p = new Process(NULL, new std::list(), transformed, node.location); // FIXME name! this->workList->push_front(p); this->sensitivities.clear(); this->pickupSignals = false; this->deleteFlag = true; } void TransformSigAssign::visit(SigAssignStat &node) { // don't traverse to target, that's already set. if (node.waveForm == NULL) { return; } // pick up any signal in the waveForm so that it can be // added to the sensitivity set. (anything apart from a time // expression) this->listTraverse(*node.waveForm); } void TransformSigAssign::visit(WaveFormElem &node) { if (node.value != NULL) { node.value->accept(*this); } } void TransformSigAssign::visit(SimpleName &node) { if (! this->pickupSignals) { return; } if (! node.isSignal()) { return; } if (! util::MiscUtil::listContainsObj(this->sensitivities, &node)) { this->sensitivities.push_back(&node); } } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/GatherImplicits.hpp0000664000175000017500000001224311162736415022131 0ustar potyrapotyra/* $Id: GatherImplicits.hpp 4411 2009-03-26 17:36:13Z potyra $ * * Gather implicitly needed variables (e.g. drivers). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GATHER_IMPLICITS_HPP_INCLUDED #define __GATHER_IMPLICITS_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" #include #include #include "frontend/misc/Driver.hpp" namespace ast { //! gather drivers and formal parameters and register these to the processes /** This visitor will gather all implicit defined entities and register * these to the process statements or callable's. * It will pickup * - drivers of signals in a process. * - formal parameters of subprogram calls * * Dependencies: NormalizeAssocs and probably a few more. */ class GatherImplicits : public TopDownVisitor { public: //! dummy c'tor, initilize members. GatherImplicits(); private: /** Visit a SigAssignStat * @param node SigAssignStat node that get's visited. */ virtual void visit(SigAssignStat& node); /** Visit a VarAssignStat * @param node VarAssignStat node that get's visited. */ virtual void visit(VarAssignStat& node); /** visit a SimpleName * @param node node that get's visited. */ virtual void visit(SimpleName &node); /** visit a Process * @param node node that get's visited. */ virtual void visit(Process &node); /** Visit a FunctionCall. * @param node FunctionCall node that get's visited. */ virtual void visit(FunctionCall &node); /** Visit a ProcCallStat. * @param node ProcCallStat node that get's visited. */ virtual void visit(ProcCallStat &node); /** Visit a FunctionDeclaration node. * @param node FunctionDeclaration node that get's visited. */ virtual void visit(FunctionDeclaration &node); /** Visit a ProcedureDeclaration node. * @param node ProcedureDeclaration node that get's visited. */ virtual void visit(ProcedureDeclaration &node); /** Visit an Architecture node. * @param node Architecture node that get's visited. */ virtual void visit(Architecture &node); /** Visit a CompInstStat node. * @param node CompInstStat node that get's visited. */ virtual void visit(CompInstStat &node); /** process a function/procedure declaration. * @param node Callable node. */ void processCallable(Callable &node); //! Process a generic LibUnit. /** This function will get called for each LibUnit (or class * derived from LibUnit) that get's visited. * * @param node LibUnit instance. */ virtual void process(LibUnit &node); /** pick up implicits (drivers, hidden formals) from * an AssociationElement with the corresponding * declaration. * @param formalDecl the corresponsing declaration of the formal. * @parma assoc AssociationElement to pick up. */ void pickupImplicits( ValDeclaration &formalDecl, AssociationElement &assoc); /** register a driver for given signal declaration. * @param decl SignalDeclaration for which a driver should get * registered. * @param n SimpleName that references the signal. * @return generated driver or present driver. */ Driver * registerDriver(const SignalDeclaration &decl, SimpleName &n); /** register a driver for given signal declaration, that possibly * isn't used, but needs to be there due to being a parameter. * @param decl SignalDeclaration for which a driver should get * registered. * @param t symbol type for the hidden name that will be generated * on the fly. * @return generated driver or present driver. */ void registerDriver(ValDeclaration &decl, enum symType t); /** register/generate a hidden formal of a subprogram call. * @param formal declaration corresponding to the formal part. * @param actualType type of the actual (needed for unconstraints) * @return SimpleName referring to the generated hidden declaration. */ SimpleName * registerFormal( const ValDeclaration *formal, TypeDeclaration *actualType); enum VMode { /** target signal expression. */ VMODE_TARGET_SIGNAL, /** target variable expression */ VMODE_TARGET_VAR, /** any read value */ VMODE_SOURCE }; //! current visitor mode enum VMode mode; /** map of current set of signal declarations to drivers */ std::map drivers; /** map of formal declarations of subprograms to * hidden formal declarations together with a Name * referring to it. */ typedef std::map< const ValDeclaration *, std::pair > formalMapT; /** map of formal declarations of subprograms to * hidden formal declarations together with a Name * referring to it. */ formalMapT formals; /** counter to make driver names unique */ unsigned int driverCounter; /** counter to make hidden formals of unconstraint arrays unique */ unsigned int uhfCounter; }; }; /* namespace ast */ #endif /* __GATHER_IMPLICITS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/ResolveSymbols.hpp0000664000175000017500000000544411162461522022030 0ustar potyrapotyra/* $Id: ResolveSymbols.hpp 4392 2009-03-25 17:01:06Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RESOLVE_SYMBOLS_HPP_INCLUDED #define __RESOLVE_SYMBOLS_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" #include "frontend/misc/SymbolTable.hpp" namespace ast { //! class used to late resolve symbols /** This class can be used to set the symbol candidates for name based nodes, * in case these couldn't get looked up yet during scanning. * The most prominent example is any association list. */ class ResolveSymbols : public TopDownVisitor { public: //! c'tor /** @param symbolTable symbol table instance. */ ResolveSymbols( SymbolTable &symbolTable ) : symTab(symbolTable), prefixCands(NULL) {} private: /** visit a SimpleName * @param node node that get's visited. */ virtual void visit(SimpleName &node); /** visit a TemporaryName * @param node node that get's visited. */ virtual void visit(TemporaryName &node); /** visit a SelectedName * @param node node that get's visited. */ virtual void visit(SelectedName &node); /** visit a AttributeName * @param node node that get's visited. */ virtual void visit(AttributeName &node); /** visit a Slice * @param node node that get's visited. */ virtual void visit(Slice &node); /** visit a Subscript * @param node node that get's visited. */ virtual void visit(Subscript &node); /** visit a FunctionCall * @param node node that get's visited. */ virtual void visit(FunctionCall &node); /** visit an AssociationElement * @param node node that get's visited. */ virtual void visit(AssociationElement &node); /** visit a ElementAssociation * @param node node that get's visited. */ virtual void visit(ElementAssociation &node); /** visit an CompInstStat * @param node node that get's visited. */ virtual void visit(CompInstStat &node); //! process a generic expression /** @param node node to process. */ virtual void process(Expression &node); //! process a generic AstNode (must not happen). /** @param node node to process. */ virtual void process(AstNode &node); //! SymbolTable instance. SymbolTable &symTab; //! typedef for symbol lists. // FIXME should probably go to DeclarativeRegion or SymbolTable typedef std::list symListT; //! prefix candidate symbols. symListT *prefixCands; }; }; /* namespace ast */ #endif /* __RESOLVE_SYMBOLS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GenCode.cpp0000664000175000017500000023770611502715757020361 0ustar potyrapotyra/* $Id: GenCode.cpp 5088 2010-12-17 17:20:47Z potyra $ * * Code generator, which transforms the abstract syntax tree into intermediate * code. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/GenCode.hpp" #include #include #include "frontend/misc/RangeSet.hpp" #include "frontend/misc/Driver.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/IfStat.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/ast/ForLoopStat.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/NextStat.hpp" #include "frontend/ast/ExitStat.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/AssertStat.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/ConstArray.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/AttributeSpecification.hpp" #include "frontend/ast/CaseStat.hpp" #include "frontend/ast/Others.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/reporting/CompileError.hpp" #include "frontend/visitor/GCArrays.hpp" #include "frontend/visitor/GCTypes.hpp" #include "frontend/visitor/GCLoops.hpp" #include "frontend/visitor/ResolveAggregates.hpp" #include "frontend/visitor/GCBuiltins.hpp" #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/visitor/LookupTypes.hpp" #include "frontend/visitor/NormalizeAssocLists.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/operands/IndirectOperand.hpp" #include "intermediate/operands/Reference.hpp" #include "intermediate/operands/RegisterFactory.hpp" #include "intermediate/opcodes/Abort.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Je.hpp" #include "intermediate/opcodes/Jne.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Jbe.hpp" #include "intermediate/opcodes/Jmp.hpp" #include "intermediate/opcodes/IMul.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/opcodes/Connect.hpp" #include "intermediate/opcodes/SetParam.hpp" #include "intermediate/opcodes/GetParam.hpp" #include "intermediate/opcodes/BeginTransfer.hpp" #include "intermediate/opcodes/EndTransfer.hpp" #include "intermediate/opcodes/Call.hpp" #include "intermediate/opcodes/Proc.hpp" #include "intermediate/opcodes/Return.hpp" #include "intermediate/opcodes/Update.hpp" #include "intermediate/opcodes/GetSig.hpp" #include "intermediate/opcodes/GetSimTime.hpp" #include "intermediate/opcodes/ROffset.hpp" #include "intermediate/opcodes/Suspend.hpp" #include "intermediate/opcodes/WakeAt.hpp" #include "intermediate/opcodes/WakeOn.hpp" #include "intermediate/opcodes/Log.hpp" #include "intermediate/container/Label.hpp" #include "intermediate/container/LabelFactory.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/container/TypeFactory.hpp" #include "intermediate/container/Type.hpp" #include "intermediate/container/TypeElement.hpp" namespace ast { /* import some names into current namespace, just to avoid lengthy types */ using namespace intermediate; GenCode::GenCode() : container( new intermediate::CodeContainer("top", NULL)), assignExpression(false), isTarget(false), sourceRegs(RegisterSet(*container)), destRegs(RegisterSet(*container)), dataOp(NULL), currentProcess(NULL), currentSubprog(NULL), assignOperation(ASSIGN_OPERATION_COPY) { } // FIXME eventually separate expression handling from rest. GenCode::GenCode(CodeContainer *cc) : container(cc), assignExpression(false), isTarget(false), sourceRegs(RegisterSet(*cc)), destRegs(RegisterSet(*cc)), dataOp(NULL), currentProcess(NULL), currentSubprog(NULL), assignOperation(ASSIGN_OPERATION_COPY) { } void GenCode::visit(Package &node) { if (node.declarations != NULL) { this->listTraverse(*node.declarations); } if (node.body != NULL) { node.body->accept(*this); } } void GenCode::visit(Architecture &node) { assert(node.entity != NULL); assert(this->archComponents.empty()); CodeContainer *current = this->container; this->container = new CodeContainer(node.entity->getICName(), current); // handle entity specific parts. // FIXME: in case more than one architecture per entity is present, // this won't work! (however that should actually be filtered // out with configurations) this->container->dataMode = CodeContainer::DATA_TRANSFER; if (node.entity->generics != NULL) { this->listTraverse(*node.entity->generics); } if (node.entity->ports != NULL) { this->listTraverse(*node.entity->ports); } this->container->dataMode = CodeContainer::DATA_STACK; if (node.entity->declarations != NULL) { this->listTraverse(*node.entity->declarations); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); } if (node.concurrentStats != NULL) { this->listTraverse(*node.concurrentStats); } this->createInitFunction(node); this->container = current; this->archComponents.clear(); } void GenCode::visit(Entity &node) { // do nothing, handled by Architecture already } void GenCode::createInitFunction(const Architecture &node) { assert(node.entity != NULL); AttributeSpecification *foreign = node.hasAttr("foreign"); if (foreign != NULL) { this->foreignInit(node, *foreign); } this->instantiateComponents(node); Return *ret = new Return(); this->container->addCode(ret); } void GenCode::foreignInit( const Architecture &node, const AttributeSpecification &foreign ) { assert(node.entity != NULL); assert(foreign.init != NULL); ConstArray *fVal = dynamic_cast(foreign.init); assert(fVal != NULL); Reference *fRef = new Reference(fVal->unsafeMakeString()); Reference *entName = new Reference(*node.entity->name); BeginTransfer *bg = new BeginTransfer(fRef, entName); this->container->addCode(bg); bg->annotate("foreign", "architecture"); /* set generics */ assert(node.entity->generics != NULL); assert(node.entity->ports != NULL); /* set generics: * reuse code for CompInstStat, but generate an * association list with a name simply referring back * to the declaration. */ std::list assocs; this->makeSelfAssociations( assocs, *node.entity->generics, node.entity->region); this->setGenericMap(fRef, assocs, true); assocs.clear(); this->makeSelfAssociations( assocs, *node.entity->ports, node.entity->region); this->setPortList(fRef, assocs, true); assocs.clear(); Call *c = new Call(fRef); this->container->addCode(c); c->annotate("foreign", "architecture"); EndTransfer *et = new EndTransfer(fRef, ImmediateOperand::getZero()); this->container->addCode(et); et->annotate("foreign", "architecture"); } template void GenCode::makeSelfAssociations( std::list &dest, const T &src, const DeclarativeRegion *lookupRegion ) { for (typename T::const_iterator i = src.begin(); i != src.end(); i++) { SimpleName *formal = NormalizeAssocLists::makeNameOfVal(*i, lookupRegion, Location("GenCode")); AssociationElement *ele = new AssociationElement(formal, formal, Location("builtin")); dest.push_back(ele); } } void GenCode::instantiateComponents(const Architecture &node) { for (std::list::const_iterator i = this->archComponents.begin(); i != this->archComponents.end(); i++) { this->instantiateComponent(**i); } } void GenCode::instantiateComponent(CompInstStat &node) { assert(node.entity != NULL); Reference *ref; AttributeSpecification *foreign = node.entity->hasAttr("foreign"); if (foreign != NULL) { assert(foreign->init != NULL); ConstArray *fVal = dynamic_cast(foreign->init); assert(fVal != NULL); ref = new Reference(fVal->unsafeMakeString()); } else { ref = new Reference(node.entity->getICName()); } assert(node.name != NULL); BeginTransfer *bg = new BeginTransfer(ref, new Reference(*node.name)); this->container->addCode(bg); if (node.genericMap != NULL) { this->setGenericMap(ref, *node.genericMap, foreign != NULL); } if (node.portMap != NULL) { this->setPortList(ref, *node.portMap, foreign != NULL); } Call *call = new Call(ref); this->container->addCode(call); EndTransfer *et = new EndTransfer(ref, ImmediateOperand::getZero()); this->container->addCode(et); if (foreign != NULL) { bg->annotate("foreign", "entity"); call->annotate("foreign", "entity"); et->annotate("foreign", "entity"); } } void GenCode::setGenericMap( Reference *cont, std::list &genericMap, bool isForeign ) { assert(cont != NULL); const char *foreign = NULL; if (isForeign) { foreign = "generic"; } for (std::list::const_iterator i = genericMap.begin(); i != genericMap.end(); i++) { this->sourceRegs = RegisterSet(*this->container); switch ((*i)->formal->baseType) { case BASE_TYPE_REAL: case BASE_TYPE_INTEGER: case BASE_TYPE_ENUM: this->setArgByValue(cont, NULL, **i, foreign, false); break; case BASE_TYPE_RECORD: /* FIXME */ assert(0); break; case BASE_TYPE_ARRAY: if ((*i)->hiddenFormal != NULL && ((*i)->actual != NULL)) { // FIXME hacky // not an open association, and the actual // is not an unconstraint array / has // hidden storage space. const SymbolDeclaration *sd = (*i)->formal->getDeclaration(); const ValDeclaration *vd = dynamic_cast( sd); assert(vd != NULL); this->setArgByBasePointerToTemporary( cont, *vd, **i, foreign); } else { // open association. // here the hidden formal is directly // used via pointer. // // or it is an association with an actual which // is an unconstraint array, where also the // pointer can be used directly. this->setArgByBasePointer(cont, NULL, **i, foreign); } break; default: assert(0); } } } void GenCode::setPortList( Reference *cont, const std::list &portList, bool isForeign ) { assert(cont != NULL); // this method assumes that the port list has already been // normalized, so that it just contains single port elements. // FIXME this won't work with conversion functions. this->isTarget = false; const char *foreign; if (isForeign) { foreign = "port"; } else { foreign = NULL; } for (std::list::const_reverse_iterator i = portList.rbegin(); i != portList.rend(); i++) { this->sourceRegs = RegisterSet(*this->container); assert((*i)->formal != NULL); switch ((*i)->formal->baseType) { case BASE_TYPE_REAL: case BASE_TYPE_INTEGER: case BASE_TYPE_ENUM: this->setArgByPointer(cont, NULL, **i, foreign); break; case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: this->setArgByBasePointer(cont, NULL, **i, foreign); break; default: // must not happen assert(0); } } } void GenCode::createInitFunction(const Process &node) { for (std::list::const_iterator i = node.drivers.begin(); i != node.drivers.end(); i++) { this->sourceRegs = RegisterSet(*this->container); // even though the signal and the driver are known, // the way how to access these is not (pointer, or // base-pointer?). (ok, driver of a Process should // always be directly via the reference, as it // cannot be a parameter!) // reuse the SimpleName stored in the driver to // find out. // first pick up destination driver (the // SimpleName is used to obtain the signal // *and* the driver depending on isTarget) this->assignOperation = ASSIGN_OPERATION_CONNECT; this->isTarget = true; this->assignExpression = false; assert((*i)->n != NULL); (*i)->n->accept(*this); // then pick up the source signal. this->destRegs = this->sourceRegs; this->sourceRegs = RegisterSet(*this->container); this->isTarget = false; this->assignExpression = true; (*i)->n->accept(*this); } this->assignExpression = false; this->assignOperation = ASSIGN_OPERATION_COPY; this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); Reference *ref = new Reference(node.getICName()); BeginTransfer *bg = new BeginTransfer(ref, new Reference("")); this->container->addCode(bg); Proc *proc = new Proc(ref); this->container->addCode(proc); EndTransfer *et = new EndTransfer(ref, ImmediateOperand::getZero()); this->container->addCode(et); } void GenCode::visit(CompInstStat &node) { assert(node.entity != NULL); assert(node.name != NULL); this->archComponents.push_back(&node); // the real instantiation is done via the init-function so no need for // anything else here. } void GenCode::visit(VarAssignStat &node) { this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); // traverse to target, storing result in reg this->assignExpression = false; this->isTarget = true; node.target->accept(*this); this->destRegs = this->sourceRegs; // traverse to source, storing result in reg this->assignExpression = true; this->isTarget = false; node.source->accept(*this); // FIXME aggregate assignments (i.e. with an aggregate as target) // are currently not supported. } void GenCode::visit(SigAssignStat &node) { this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); assert(node.target); assert(node.waveForm); this->isTarget = true; this->assignExpression = false; node.target->accept(*this); this->destRegs = this->sourceRegs; this->isTarget = false; //traverse to waveform elements for (std::list::const_iterator i = node.waveForm->begin(); i != node.waveForm->end(); i++) { this->sourceRegs = RegisterSet(*this->container); if ((*i)->delay != NULL) { (*i)->accept(*this); this->dataOp = this->sourceRegs.getValue( (*i)->delay->baseType); this->sourceRegs = RegisterSet(*this->container); } else { this->dataOp = ImmediateOperand::getZero(); } this->assignExpression = true; assert((*i)->value != NULL); (*i)->value->accept(*this); } this->dataOp = NULL; } void GenCode::visit(SimpleName &node) { assert(node.candidates.size() == 1); Symbol *sym = node.candidates.front(); bool refPointer = false; // sanity check only switch(sym->type) { case SYMBOL_VARIABLE: break; case SYMBOL_SIGNAL: break; case SYMBOL_PARAMETER: switch (node.baseType) { case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: refPointer = true; break; default: break; } break; case SYMBOL_PORT: switch (node.baseType) { case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: if (! this->isTarget) { // the ports means that the // driver is *always* locally stored. refPointer = true; } break; default: break; } break; default: std::cerr << "At " << node.location << ": unexpected symbol found: " << *sym << std::endl; assert(false); } ProcessStackedExpression pse = ProcessStackedExpression(*this, node); this->sourceRegs = RegisterSet(*this->container); Reference *ref; if (this->isTarget && node.isSignal()) { assert(node.driver != NULL); ref = new Reference(node.driver->getICName()); } else { ref = new Reference(node.getName()); } Operand *op = ref; if (refPointer) { Register *ptr = this->container->createRegister(OP_TYPE_POINTER); Mov *m = new Mov(ref, ptr); this->container->addCode(m); op = new IndirectOperand(ptr, OP_TYPE_POINTER); } // check for unconstraint arrays. const ValDeclaration *decl = dynamic_cast( node.getDeclaration()); assert(decl != NULL); if (decl->isUnconstraint()) { this->getConstraints(*decl); } this->sourceRegs.setPointer(op); this->sourceRegs.isSignal = node.isSignal(); } void GenCode::visit(ConstInteger &node) { ProcessStackedExpression pse = ProcessStackedExpression(*this, node); this->processConst(node); } void GenCode::visit(ConstReal &node) { ProcessStackedExpression pse = ProcessStackedExpression(*this, node); this->processConst(node); } void GenCode::visit(IfStat &node) { this->assignExpression = false; // generate code for condition node.condition->accept(*this); ImmediateOperand *trueOp = new ImmediateOperand( static_cast(VHDL_TRUE)); Label *thenLabel = LabelFactory::getLabel("then"); Operand *condOp = this->sourceRegs.getValue(node.condition->baseType); Je *condJmp = new Je(condOp, trueOp, thenLabel); this->container->addCode(condJmp); Label *endIf = LabelFactory::getLabel("endif"); Label *elseLbl = NULL; if (node.elseStats != NULL) { elseLbl = LabelFactory::getLabel("else"); Jmp *ej = new Jmp(elseLbl); this->container->addCode(ej); } else { Jmp *out = new Jmp(endIf); this->container->addCode(out); } assert(node.thenStats != NULL); this->container->addCode(thenLabel); this->listTraverse(*node.thenStats); if (node.elseStats != NULL) { Jmp *out = new Jmp(endIf); this->container->addCode(out); this->container->addCode(elseLbl); this->listTraverse(*node.elseStats); } this->container->addCode(endIf); } void GenCode::visit(Process &node) { CodeContainer *current = this->container; this->container = new CodeContainer(node.getICName(), current); if (node.declarations != NULL) { this->listTraverse(*node.declarations); } this->currentProcess = &node; std::string runS = node.getICName() + "_run"; Label *runL = LabelFactory::getFixedLabel(runS); // FIXME how to handle implicit variables? this->container->addCode(runL); if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); } Jmp *loop = new Jmp(runL); this->container->addCode(loop); this->currentProcess = NULL; this->container = current; // register drivers in *architecture* this->registerDrivers(node); // also add init function code to *architecture* this->createInitFunction(node); } void GenCode::registerDrivers(const Process &node) { for (std::list::const_iterator i = node.drivers.begin(); i != node.drivers.end(); i++) { this->registerDriver(**i); } } void GenCode::registerDriver(Driver &drv) { std::string name = drv.getICName(); GCTypes::GenTypeElements gte = GCTypes::GenTypeElements(true, "FIXME", drv.signal, NULL); assert(drv.signal.subtypeIndic != NULL); drv.signal.subtypeIndic->accept(gte); assert(gte.composite.size() == 1); TypeElement *te = gte.composite.front(); Data *d = new Data(name, STORAGE_TYPE_DRIVER, te, NULL); this->container->addData(d); } void GenCode::visit(ForLoopStat &node) { class LoopImpl : public ForLoopIterate { public: LoopImpl( intermediate::CodeContainer &container, intermediate::Operand &counter, intermediate::Operand &initializer, intermediate::Operand &rightBound, bool isAscending, GenCode &genCode, ForLoopStat &nd ) : ForLoopIterate( container, counter, initializer, rightBound, isAscending), gc(genCode), loopNode(nd) {} private: // cppcheck-suppress unusedPrivateFunction (false positive) virtual void loopBody(void) { gc.listTraverse(*this->loopNode.loopStats); } GenCode &gc; ForLoopStat &loopNode; }; assert(node.loopStats != NULL); assert(node.range != NULL); assert(node.loopVariable != NULL); assert(node.loopVariable->subtypeIndic != NULL); assert(node.loopVariable->subtypeIndic->baseType == BASE_TYPE_INTEGER); // add declaration for loop variable node.loopVariable->accept(*this); bool asc = node.range->direction == DiscreteRange::DIRECTION_UP; this->assignExpression = false; this->sourceRegs = RegisterSet(*this->container); node.range->accept(*this); assert(this->sourceRegs.sliceBegin != NULL); assert(this->sourceRegs.sliceEnd != NULL); Reference *ref = new Reference(node.loopVariable->getICName()); Register *loopVarP = this->container->createRegister(OP_TYPE_POINTER); Mov *mov = new Mov(ref, loopVarP); this->container->addCode(mov); Operand *cnt = new IndirectOperand(loopVarP, OP_TYPE_INTEGER); Operand *left = this->sourceRegs.sliceBegin; Operand *right = this->sourceRegs.sliceEnd; this->sourceRegs = RegisterSet(*this->container); LoopImpl li = LoopImpl( *this->container, *cnt, *left, *right, asc, *this, node); this->loopRegistry.rememberLoop(&node, &li); li.addIteration(); this->loopRegistry.forgetLoop(&node); } void GenCode::visit(WhileLoopStat &node) { class WLImpl : public WhileIterate { public: WLImpl( CodeContainer &container, GenCode &genCode, WhileLoopStat &n ) : WhileIterate(container), gc(genCode), nd(n) {} private: // cppcheck-suppress unusedPrivateFunction (false positive) virtual void initializeCounter(void) { // do nothing. } // cppcheck-suppress unusedPrivateFunction (false positive) virtual void checkCondition(void) { this->gc.sourceRegs = RegisterSet(*this->gc.container); this->gc.destRegs = RegisterSet(*this->gc.container); this->gc.assignExpression = false; assert(this->nd.condition != NULL); this->nd.condition->accept(this->gc); Operand *condOp = this->gc.sourceRegs.getValue( this->nd.condition->baseType); ImmediateOperand *trueOp = new ImmediateOperand( static_cast( VHDL_TRUE)); Jne *jne = new Jne( trueOp, condOp, this->loopDone); this->cc.addCode(jne); this->gc.sourceRegs = RegisterSet(*this->gc.container); } // cppcheck-suppress unusedPrivateFunction (false positive) virtual void incCounter(void) { // nothing to do } // cppcheck-suppress unusedPrivateFunction (false positive) virtual void loopBody(void) { if (this->nd.loopStats == NULL) { return; } this->gc.listTraverse(*nd.loopStats); } GenCode &gc; WhileLoopStat &nd; }; WLImpl loop = WLImpl(*this->container, *this, node); this->loopRegistry.rememberLoop(&node, &loop); loop.addIteration(); this->loopRegistry.forgetLoop(&node); } void GenCode::visit(NextStat &node) { assert(node.referredLoop != NULL); WhileIterate *wl = this->loopRegistry.lookup(node.referredLoop); assert(wl->loopInc != NULL); this->processCFLoopStat(node.condition, wl->loopInc); } void GenCode::visit(ExitStat &node) { assert(node.referredLoop != NULL); WhileIterate *wl = this->loopRegistry.lookup(node.referredLoop); assert(wl->loopDone != NULL); this->processCFLoopStat(node.condition, wl->loopDone); } void GenCode::visit(WaitStat &node) { this->sourceRegs = RegisterSet(*this->container); this->assignExpression = false; this->isTarget = false; Label *loopLbl = NULL; Label *exitWait = NULL; Register *resumeAt = NULL; // semantics of a wait: // time := now() + timeout // loop // trigger(self, time) // trigger_sig(self, signal_list) // suspend() // time1 := now() // exit if time1 >= time -- timeout // if !condition goto loop -- condition met // end loop // time := now() + timeout if (node.timeout != NULL) { node.timeout->accept(*this); Operand *timeout = this->sourceRegs.getValue(node.timeout->baseType); assert(timeout != NULL); // now := now(); Register *now = this->container->createRegister(OP_TYPE_INTEGER); GetSimTime *gst = new GetSimTime(now); this->container->addCode(gst); resumeAt = this->container->createRegister(OP_TYPE_INTEGER); Add *cra = new Add(now, timeout, resumeAt); this->container->addCode(cra); } // loop ... if (node.condition != NULL) { loopLbl = LabelFactory::getLabel("wait_until_loop"); this->container->addCode(loopLbl); exitWait = LabelFactory::getLabel("wait_done"); } // trigger(self, time) if (node.timeout != NULL) { WakeAt *wa = new WakeAt(resumeAt); this->container->addCode(wa); } // trigger_sig(self, signal_list) // sensitivities must have been set by WaitConditions visitor. assert(node.sensitivities != NULL); for (std::list::iterator i = node.sensitivities->begin(); i != node.sensitivities->end(); i++) { this->sourceRegs = RegisterSet(*this->container); this->assignOperation = ASSIGN_OPERATION_WAKEON; this->assignExpression = true; (*i)->accept(*this); } this->assignExpression = false; this->assignOperation = ASSIGN_OPERATION_COPY; //suspend Suspend *suspend = new Suspend(); this->container->addCode(suspend); // exit if now() >= time -- timeout if ((node.timeout != NULL) && (node.condition != NULL)) { Register *now = this->container->createRegister(OP_TYPE_INTEGER); GetSimTime *gst = new GetSimTime(now); this->container->addCode(gst); Jbe *exitTimout = new Jbe(resumeAt, now, exitWait); this->container->addCode(exitTimout); } // if !condition goto loop if (node.condition != NULL) { this->sourceRegs = RegisterSet(*this->container); node.condition->accept(*this); Operand *cond = this->sourceRegs.getValue(BASE_TYPE_INTEGER); Jne *goLoop = new Jne(cond, ImmediateOperand::getOne(), loopLbl); this->container->addCode(goLoop); this->sourceRegs = RegisterSet(*this->container); this->container->addCode(exitWait); } } void GenCode::visit(AssertStat &node) { assert(node.condition != NULL); this->assignExpression = false; this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); node.condition->accept(*this); //evaluate condition Label *assertSuccL = LabelFactory::getLabel("assert_succ"); Operand *cond = this->sourceRegs.getValue(node.condition->baseType); Je *je = new Je(cond, new ImmediateOperand( static_cast(VHDL_TRUE)), assertSuccL); this->container->addCode(je); // severity present? if (node.severity != NULL) { this->sourceRegs = RegisterSet(*this->container); node.severity->accept(*this); this->dataOp = this->sourceRegs.getValue(BASE_TYPE_INTEGER); } else { // no severity -> error (lrm 8.2) this->dataOp = new ImmediateOperand( static_cast(2)); } Operand *severityOp = this->dataOp; // log VHDL position std::string loc = util::MiscUtil::toString(node.location); loc += ": "; for (std::string::const_iterator i = loc.begin(); i != loc.end(); i++) { ImmediateOperand *charVal = new ImmediateOperand( static_cast(*i)); Log *l = new Log(this->dataOp, charVal); this->dataOp = new ImmediateOperand( static_cast(-1)); this->container->addCode(l); } if (node.report != NULL) { this->assignExpression = true; this->assignOperation = ASSIGN_OPERATION_LOG; node.report->accept(*this); this->assignOperation = ASSIGN_OPERATION_COPY; this->assignExpression = false; // add a newline universal_integer newline = '\n'; universal_integer mo = -1; Log *l = new Log(new ImmediateOperand(mo), new ImmediateOperand(newline)); this->container->addCode(l); // abort if severity is FAILURE universal_integer sevError = 3; Jb *jb = new Jb(severityOp, new ImmediateOperand(sevError), assertSuccL); Abort *a = new Abort(); this->container->addCode(jb); this->container->addCode(a); } else { // TODO Log "Assertion violation." } this->container->addCode(assertSuccL); this->dataOp = NULL; } void GenCode::visit(ProcCallStat &node) { this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); assert(node.definition != NULL); AttributeSpecification *foreign = node.definition->hasAttr("foreign"); const char *fattr = NULL; if (foreign != NULL) { fattr = "procedure"; } this->callSubprog(node, fattr); } void GenCode::visit(ConstArray &node) { assert(this->assignExpression); switch (this->assignOperation) { case ASSIGN_OPERATION_COPY: if (this->destRegs.isSignal) { this->processArrayUpdate(node); } else { this->processArrayCopy(node); } break; case ASSIGN_OPERATION_LOG: // only the first character should get logged with // level in dataOp, the rest with -1 (so that // level will only be printed for the first // character) for (std::vector::iterator i = node.elements->begin(); i != node.elements->end(); i++) { (*i)->accept(*this); if (i == node.elements->begin()) { universal_integer mo = -1; this->dataOp = new ImmediateOperand(mo); } } break; case ASSIGN_OPERATION_CONNECT: // mustn't happen assert(false); break; case ASSIGN_OPERATION_WAKEON: for (std::vector::iterator i = node.elements->begin(); i != node.elements->end(); i++) { (*i)->accept(*this); } break; }; } void GenCode::processArrayCopy(ConstArray &node) { class ConstArrayAssign : public StaticArrayIterate { public: ConstArrayAssign( TypeDeclaration *at, Operand *b, CodeContainer &container, ConstArray &nod ) : StaticArrayIterate(at, b, container), ca(nod) {} private: ConstArray &ca; // cppcheck-suppress unusedPrivateFunction (false positive) virtual void iterateBody( Register *element, std::list indics) { universal_integer i = indics.front(); i = ArrayHandling::transform_idx(this->arrayType, i); unsigned int ri = static_cast(i); assert(static_cast(ri) == i); assert(ri < this->ca.elements->size()); ConstInteger *ci = (*this->ca.elements)[ri]; universal_integer value = ci->value; IndirectOperand *valOp = new IndirectOperand(element, OP_TYPE_INTEGER); Mov *m = new Mov(new ImmediateOperand(value), valOp); this->cc.addCode(m); } }; ConstArrayAssign caa = ConstArrayAssign(node.type, this->destRegs.getPointer(), *this->container, node); caa.iterate(); } void GenCode::processArrayUpdate(ConstArray &node) { class ConstArrayAssign : public StaticArrayIterate { public: ConstArrayAssign( TypeDeclaration *at, Operand *b, CodeContainer &container, ConstArray &nod, Operand *delay ) : StaticArrayIterate(at, b, container), ca(nod), delayOp(delay) {} private: ConstArray &ca; Operand *delayOp; // cppcheck-suppress unusedPrivateFunction (false positive) virtual void iterateBody( Register *element, std::list indics) { universal_integer i = indics.front(); i = ArrayHandling::transform_idx(this->arrayType, i); unsigned int ri = static_cast(i); assert(static_cast(ri) == i); assert(ri < this->ca.elements->size()); ConstInteger *ci = (*this->ca.elements)[ri]; universal_integer value = ci->value; IndirectOperand *drvPtr = new IndirectOperand(element, OP_TYPE_POINTER); Update *up = new Update(new ImmediateOperand(value), this->delayOp, drvPtr); this->cc.addCode(up); } }; ConstArrayAssign caa = ConstArrayAssign(node.type, this->destRegs.getPointer(), *this->container, node, this->dataOp); caa.iterate(); } void GenCode::processCFLoopStat(Expression *optCond, Label *target) { assert(target != NULL); if (optCond == NULL) { Jmp *jmp = new Jmp(target); this->container->addCode(jmp); return; } // optCond != NULL this->sourceRegs = RegisterSet(*this->container); this->assignExpression = false; optCond->accept(*this); Operand *cond = this->sourceRegs.getValue(optCond->baseType); ImmediateOperand *trueOp = new ImmediateOperand( static_cast(VHDL_TRUE)); Je *jcond = new Je(cond, trueOp, target); this->container->addCode(jcond); this->sourceRegs = RegisterSet(*this->container); } template void GenCode::processConst(T &node) { this->sourceRegs = RegisterSet(*this->container); this->sourceRegs.setValue(new ImmediateOperand(node.value)); } void GenCode::visit(Subscript &node) { ProcessStackedExpression pse = ProcessStackedExpression(*this, node); assert(node.indices != NULL); assert(node.source != NULL); node.source->accept(*this); assert(! node.indices->empty()); this->processSubscription(node, *node.indices); } void GenCode::processSubscription(Subscript &node, std::list &indices) { std::list idcs = std::list(); for (std::list::iterator i = indices.begin(); i != indices.end(); i++) { Operand *value = this->getSubscriptIndex(*i); idcs.push_back(value); } this->sourceRegs.subscribe(node.source->type, idcs); } intermediate::Operand * GenCode::getSubscriptIndex(Expression *index) { bool backupIsTarget = this->isTarget; RegisterSet backupRegs = this->sourceRegs; this->sourceRegs = RegisterSet(*this->container); this->isTarget = false; index->accept(*this); this->isTarget = backupIsTarget; RegisterSet ret = this->sourceRegs; this->sourceRegs = backupRegs; return ret.getValue(index->baseType); } void GenCode::visit(Slice &node) { ProcessStackedExpression pse = ProcessStackedExpression(*this, node); assert(node.source != NULL); // traverse to source node.source->accept(*this); // backup transfer registers RegisterSet backupRegs = this->sourceRegs; this->sourceRegs = RegisterSet(*this->container); bool backupIsTarget = this->isTarget; this->isTarget = false; // traverse to range assert(node.range != NULL); node.range->accept(*this); // FIXME did the slice narrow/boundary check. backupRegs.sliceBegin = this->sourceRegs.sliceBegin; backupRegs.sliceEnd = this->sourceRegs.sliceEnd; this->sourceRegs = backupRegs; this->isTarget = backupIsTarget; } void GenCode::visit(DiscreteRange &node) { if (node.from != NULL) { assert(node.to != NULL); this->processDRByBounds(node); return; } if (node.rangeName != NULL) { node.rangeName->accept(*this); return; } assert(false); } void GenCode::processDRByBounds(DiscreteRange &node) { assert(node.from != NULL); assert(node.to != NULL); node.from->accept(*this); Operand *sliceFrom = this->sourceRegs.getValue(node.from->baseType); this->sourceRegs = RegisterSet(*this->container); node.to->accept(*this); Operand *sliceTo = this->sourceRegs.getValue(node.to->baseType); this->sourceRegs = RegisterSet(*this->container); switch (node.direction) { case DiscreteRange::DIRECTION_UP: this->sourceRegs.sliceBegin = sliceFrom; this->sourceRegs.sliceEnd = sliceTo; break; case DiscreteRange::DIRECTION_DOWN: this->sourceRegs.sliceBegin = sliceTo; this->sourceRegs.sliceEnd = sliceFrom; break; default: // must not happen assert(false); } } void GenCode::visit(AttributeName &node) { if ((*node.name) == std::string("range")) { this->processRangeAttr(node); return; } if ((*node.name) == std::string("event")) { // FIXME needs a new opcode to evaluate 'event // (maybe combine with 'active etc.?) // // currently just say "yes" for 'event. lalala this->sourceRegs = RegisterSet(*this->container); this->sourceRegs.setValue(ImmediateOperand::getOne()); return; } // TODO assert(0); } void GenCode::processRangeAttr(AttributeName &node) { // FIXME maybe the static part should go to constant propagation? std::list staticResolution; ResolveTypes::pickupIndexConstraint(node.type, staticResolution); if (! staticResolution.empty()) { DiscreteRange *dr = staticResolution.front(); dr->accept(*this); return; } // need to resolve at run time (unconstraint arrays) assert(this->assignExpression == false); assert(! this->isTarget); node.prefix->accept(*this); std::list lbs; std::list ubs; std::list dirs; this->sourceRegs.getConstraints(lbs, ubs, dirs); assert(! lbs.empty()); assert(! ubs.empty()); assert(! dirs.empty()); // TODO direction this->sourceRegs.sliceBegin = lbs.front(); this->sourceRegs.sliceEnd = ubs.front(); lbs.clear(); ubs.clear(); dirs.clear(); // clear unconstraint state this->sourceRegs.setUnconstraintBounds(lbs, ubs, dirs); } void GenCode::visit(SelectedName &node) { ProcessStackedExpression pse = ProcessStackedExpression(*this, node); assert(node.prefix); //traverse to prefix node.prefix->accept(*this); assert(this->sourceRegs.sliceBegin == NULL); assert(this->sourceRegs.sliceEnd == NULL); assert(node.candidates.size() == 1); Symbol *sym = node.candidates.front(); // symbol must be a RecordTypeElement RecordTypeElement *elem = dynamic_cast(&sym->declaration); assert(elem != NULL); ImmediateOperand *off = new ImmediateOperand(elem->offset); Type *rt = TypeFactory::lookupType(elem->parent->getICName()); assert(rt != NULL); Register *r = this->container->createRegister(OP_TYPE_POINTER); ROffset *selection = new ROffset(this->sourceRegs.getPointer(), off, rt, r); this->sourceRegs.setPointer(r); this->container->addCode(selection); } void GenCode::visit(FunctionCall &node) { ProcessStackedExpression pse = ProcessStackedExpression(*this, node); assert(! this->isTarget); if (node.definition->isBuiltin) { if (node.definition->gcBuiltin == NULL) { std::cerr << "WARNING: builtin, but then again not a " << "builtin: " << *node.definition->name << std::endl; } assert(node.definition->gcBuiltin != NULL); assert(node.arguments != NULL); this->sourceRegs = node.definition->gcBuiltin->emitCode( *this, *node.arguments); return; } // not a builtin. AttributeSpecification *foreign = node.definition->hasAttr("foreign"); const char *fattr = NULL; if (foreign != NULL) { fattr = "function"; } Register *ret = this->callSubprog(node, fattr); enum BaseType bt = node.definition->returnType->baseType; switch(bt) { case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: case BASE_TYPE_ENUM: this->sourceRegs.setValue(ret); break; case BASE_TYPE_RECORD: case BASE_TYPE_ARRAY: this->handleCompositeReturn(node); break; default: assert(false); } } void GenCode::visit(Aggregate &node) { switch(node.baseType) { case BASE_TYPE_ARRAY: this->processArrayAggregate(node); break; case BASE_TYPE_RECORD: this->processRecordAggregate(node); break; default: std::cerr << "strange Aggregate at " << node.location << ": " << node << std::endl; // not valid for an Aggregate assert(false); } } void GenCode::processArrayAggregate(Aggregate &node) { // hints from lrm, p.109: // if a choice is present, it must be locally static // the only exception is, if there is // - just one associaton *and* // - this one has only one choice assert(this->assignExpression); // FIXME assert(node.associations != NULL); // determine index constraint. std::list idcs = std::list(); // TODO? return value is the base type. ResolveTypes::pickupIndexConstraint(node.type, idcs); assert(idcs.size() > 0); DiscreteRange *neededIndex = idcs.front(); // resolve arrray ranges ResolveAggregates ra = ResolveAggregates(*neededIndex); node.accept(ra); assert(node.associations != NULL); for (std::list::iterator i = node.associations->begin(); i != node.associations->end(); i++) { this->processArrayAssoc(**i, node.type); } } void GenCode::processArrayAssoc(ElementAssociation &node, TypeDeclaration *aType) { if (node.range == NULL) { // error occured beforehand, reported already. return; } // lrm 7.3.2: reinterpeted: // a <= (1 to 3 | 5 => '1', others => '0') // means that each array element of a, that falls in the choices // 1 to 3 | 5 gets '1' assigned, and each element that falls in // the choices others gets '0' assigned. // // In particular, this means to do a subscript for each element of a, // and put the result of the actual in there. // // One possible approach is to iterate over each element of the ranges // and assign the first result to the first element of a and reuse // that space as a cache for the remaining elements of a choice. // empty Range? -> do nothing. (might happen in case of "Others" // referring to an empty Range). RangeSet rs = *node.range; if (rs.empty()) { return; } // subscribe to first element of choices, and let the actual do the // assignment in the first place. RegisterSet dRegs = this->destRegs; // FIXME think about slices? this->destRegs = RegisterSet(this->destRegs); assert(node.actual != NULL); std::list indices = std::list(); universal_integer i = rs.getLowerBound(); ImmediateOperand *idx = new ImmediateOperand(i); indices.push_back(idx); this->destRegs.subscribe(aType, indices); // determine value of actual (and also assign it to the first // destination offset) node.actual->accept(*this); bool ret = rs.minus(i, i); assert(ret); // prepare to handle remaining elements. use the evaluated element // that was just assigned as source. // FIXME this only works for variables, not for signals! this->sourceRegs = this->destRegs; assert(! this->sourceRegs.isSignal); while (! rs.empty()) { // determine new destination index for the next element indices.clear(); i = rs.getLowerBound(); indices.push_back(new ImmediateOperand(i)); this->destRegs = RegisterSet(dRegs); this->destRegs.subscribe(aType, indices); // assign it this->doAssignment(*node.actual->type); // remove the next index from the set. ret = rs.minus(i, i); assert(ret); } this->destRegs = dRegs; } void GenCode::processRecordAggregate(Aggregate &node) { // TODO assert(false); } void GenCode::visit(ReturnStat &node) { // TODO see comment for FunctionDeclaration's visit method if (node.result != NULL) { /* FIXME composite results... there needs to be * an assignment! */ this->destRegs = RegisterSet(*this->container); this->sourceRegs = RegisterSet(*this->container); Reference *retRef = new Reference("__return__"); this->destRegs.setPointer(retRef); this->assignExpression = true; node.result->accept(*this); this->assignExpression = false; this->destRegs = RegisterSet(*this->container); switch(node.result->baseType) { case BASE_TYPE_ENUM: case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: break; case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: /* TODO allocate space on stack, and have a pointer * return register point to it */ assert(false); break; default: /* must not happen */ assert(false); } } Return *ret = new Return(); this->container->addCode(ret); } void GenCode::visit(SignalDeclaration &node) { // FIXME for procedures, skip OUT signals (only driver needed) Data *d = this->processValDecl(node, STORAGE_TYPE_SIGNAL); if (d == NULL) { return; } // annotate foreign signals if ((node.usage & ValDeclaration::USAGE_FOREIGN) == 0) { // not foreign return; } // lookup base type // FIXME this doesn't work well for composite types and needs further // thoughts. // // array -> element type? // or // array -> array type? (might also be a mapping?) // // record -> ??? assert(node.subtypeIndic != NULL); LookupTypes lat = LookupTypes(true, true); node.subtypeIndic->accept(lat); assert(lat.declaration != NULL); assert(lat.declaration->name != NULL); d->annotate("foreign", *lat.declaration->name); if ((node.usage & ValDeclaration::USAGE_READ) != 0) { d->annotate("read", 1); } // don't care about writes, Driver must handle this. } Data * GenCode::processValDecl(ValDeclaration &node, enum StorageType st) { // skip unused declarations (but *not* signals, as these might be // ports. // FIXME this shouldn't be done in GenCode, but rather beforehand. // Ports are a little bit problematic though. If unused, // NormalizeAssocs will add unassociated ports as association // elements. // If used in a port map statement, the port is signal is // "kind of" used, i.e. it shouldn't get optimized out -- // unless the association is *also* removed. #if 0 /* FIXME deficiency in WarnUnused */ if ( (node.usage == ValDeclaration::USAGE_NONE) && (st != STORAGE_TYPE_SIGNAL)) { return NULL; } #endif bool usePointer = false; // for transfer segments: // * signals/drivers will always be passed as pointers // * records/arrays will always be passed as pointers switch (this->container->dataMode) { case CodeContainer::DATA_TRANSFER: switch (st) { case STORAGE_TYPE_SIGNAL: case STORAGE_TYPE_DRIVER: usePointer = true; break; default: switch (node.subtypeIndic->baseType) { case BASE_TYPE_RECORD: case BASE_TYPE_ARRAY: usePointer = true; break; default: break; } } default: break; } if (usePointer) { std::list initial = std::list(); initial.push_back(ImmediateOperand::getZero()); TypeElement *typeE = new TypeElement("__pointer__", initial, 1); Data *d = new Data(node.getICName(), STORAGE_TYPE_VARIABLE, typeE, NULL); this->container->addData(d); if (node.isUnconstraint()) { this->addUnconstraintParams(node); } return d; } GCTypes::GenTypeElements gte = GCTypes::GenTypeElements(true, "Cannot instantiate a data type " "of an unconstraint array.", node, node.init); assert(node.subtypeIndic != NULL); node.subtypeIndic->accept(gte); if (gte.composite.size() != 1) { //error (already reported, hopefully), e.g. //instantiating an unconstraint array. return NULL; } TypeElement *te = gte.composite.front(); std::string *resolver = NULL; switch (st) { case STORAGE_TYPE_SIGNAL: resolver = node.subtypeIndic->getResolver(); break; default: break; } Data *d = new Data(node.getICName(), st, te, resolver); this->container->addData(d); GenCode::annotateDataSize(*d, node.subtypeIndic); return d; } void GenCode::visit(VarDeclaration &node) { this->processValDecl(node, STORAGE_TYPE_VARIABLE); } void GenCode::visit(ConstantDeclaration &node) { this->processValDecl(node, STORAGE_TYPE_VARIABLE); } void GenCode::visit(SubtypeIndication &node) { this->process(node); } void GenCode::visit(FunctionDeclaration &node) { CodeContainer *child = this->processCallable(node); if (child == NULL) { // error found (and reported) or foreign subprogram. return; } // TODO better idea would be to remap function calls to // procedure calls and add an out variable // that contains the return value. // This is a little bit tricky to get right though. // (cf. NormalizeAssocs, GatherImplicits) child->dataMode = CodeContainer::DATA_TRANSFER; // add transfer element for the return type. switch (node.returnType->baseType) { case BASE_TYPE_ENUM: case BASE_TYPE_INTEGER: { ImmediateOperand *retInit = ImmediateOperand::getZero(); std::string btn = TypeFactory::getTypeName( node.returnType->baseType); std::list initVs = std::list(); initVs.push_back(retInit); Data *d = new Data("__return__", STORAGE_TYPE_VARIABLE, new TypeElement(btn, initVs), NULL); child->addData(d); break; } case BASE_TYPE_REAL: { ImmediateOperand *retInit = new ImmediateOperand(0.0); std::string btn = TypeFactory::getTypeName( node.returnType->baseType); std::list initVs = std::list(); initVs.push_back(retInit); Data *d = new Data("__return__", STORAGE_TYPE_VARIABLE, new TypeElement(btn, initVs), NULL); child->addData(d); break; } case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: // TODO assert(false); break; default: assert(false); break; } child->dataMode = CodeContainer::DATA_STACK; } void GenCode::visit(ProcedureDeclaration &node) { this->processCallable(node); } intermediate::CodeContainer * GenCode::processCallable(Callable &node) { if (node.hasAttr("foreign") != NULL) { // foreign subprogram if (node.definition != NULL) { CompileError *ce = new CompileError(node, "Implementation of foreign " "subprogram found."); ErrorRegistry::addError(ce); } return NULL; } if (node.definition == NULL) { CompileError *ce = new CompileError(node, "Subprogram declaration w.o. specification."); ErrorRegistry::addError(ce); return NULL; } CodeContainer *current = this->container; CodeContainer *spc = new CodeContainer(node.getICName(), current); this->container = spc; this->container->dataMode = CodeContainer::DATA_TRANSFER; if (node.arguments != NULL) { this->listTraverse(*node.arguments); } for (std::list::const_iterator i = node.drivers.begin(); i != node.drivers.end(); i++) { // only the pointer to the driver is transferred, so // it's a variable of type pointer. std::list initVs = std::list(); initVs.push_back(ImmediateOperand::getZero()); TypeElement *te = new TypeElement("__pointer__", initVs); Data *d = new Data((*i)->getICName(), STORAGE_TYPE_VARIABLE, te, NULL); this->container->addData(d); } this->container->dataMode = CodeContainer::DATA_STACK; this->currentSubprog = &node; node.definition->accept(*this); this->currentSubprog = NULL; Return *ret = new Return(); this->container->addCode(ret); this->container = current; return spc; } void GenCode::process(TypeDeclaration &node) { if (node.name == NULL) { return; } GCTypes::GenTypes gt = GCTypes::GenTypes(); node.accept(gt); if (gt.type != NULL) { this->container->addType(gt.type); } } void GenCode::processExpression(Expression &node) { if (! this->assignExpression) { return; } assert(node.type != NULL); this->doAssignment(*node.type); } void GenCode::doAssignment(TypeDeclaration &type) { RegisterSet *dest = NULL; switch (this->assignOperation) { case ASSIGN_OPERATION_CONNECT: case ASSIGN_OPERATION_COPY: dest = &this->destRegs; break; case ASSIGN_OPERATION_LOG: case ASSIGN_OPERATION_WAKEON: // only needs one RegisterSet break; } AssignVisitor av = AssignVisitor( &this->sourceRegs, dest, *this->container, this->dataOp, this->assignOperation); type.accept(av); } template Register * GenCode::callSubprog(T &node, const char *foreign) { // FIXME This violates the semantics of the intermediate code: // Doing it like this can result in // begintransfer // ... // begintransfer (from an argument) // call // endtransfer // ... // endtransfer // // TODO: write a test-case for this. assert(node.definition != NULL); std::list copyBackFormals = std::list(); // FIXME make use of foreign. Reference *subprog; if (foreign != NULL) { subprog = new Reference(*node.definition->name); } else { subprog = new Reference(node.definition->getICName()); } BeginTransfer *bg = new BeginTransfer(subprog, new Reference("")); this->container->addCode(bg); if (foreign != NULL) { bg->annotate("foreign", foreign); } if (node.arguments != NULL) { RegisterSet backup = this->destRegs; bool assignExp = this->assignExpression; this->assignExpression = false; copyBackFormals = this->setArgList(node, foreign); this->destRegs = backup; this->assignExpression = assignExp; } Call *c = new Call(subprog); this->container->addCode(c); if (foreign != NULL) { c->annotate("foreign", foreign); } // copy back formals... for (std::list::const_iterator i = copyBackFormals.begin(); i != copyBackFormals.end(); i++) { this->container->addCode(*i); } Register *ret = getReturnValue(node, subprog); ImmediateOperand *trueOp = ImmediateOperand::getOne(); EndTransfer *et = new EndTransfer(subprog, trueOp); if (foreign != NULL) { et->annotate("foreign", foreign); } this->container->addCode(et); return ret; } template <> Register * GenCode::getReturnValue(ProcCallStat &node, Reference *callee) { // no return value for procedures. return NULL; } template <> Register * GenCode::getReturnValue(FunctionCall &node, Reference *callee) { Reference *ref = new Reference("__return__"); Register *ret = this->container->createRegister( toOpType(node.definition->returnType->baseType)); GetParam *gp = new GetParam(ref, callee, ret); // TODO foreign returns this->container->addCode(gp); return ret; } template std::list GenCode::setArgList(T &node, const char *foreign) { std::list ret = std::list(); OpCode *op; assert(node.arguments != NULL); assert(node.definition != NULL); assert(node.definition->arguments != NULL); std::list::iterator j = node.definition->arguments->begin(); for (std::list::iterator i = node.arguments->begin(); i != node.arguments->end(); i++, j++) { // FIXME individual association op = this->setArg(*node.definition, **j, **i, foreign); if (op) { ret.push_back(op); } } return ret; } intermediate::OpCode * GenCode::setArg( Callable &c, const ValDeclaration &vd, AssociationElement &element, const char *foreign ) { //FIXME individiual association? // imo this *should* have been cleared somewhere else. (but is not) assert(element.formal == NULL); assert(element.actual != NULL); assert(! this->isTarget); assert(! this->assignExpression); Reference *callee = NULL; if (foreign != NULL) { callee = new Reference(*c.name); } else { callee = new Reference(c.getICName()); } OpCode *op = NULL; this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); switch (vd.storageClass) { case ValDeclaration::OBJ_CLASS_CONSTANT: switch (element.actual->baseType) { case BASE_TYPE_INTEGER: case BASE_TYPE_ENUM: case BASE_TYPE_REAL: this->setArgByValue(callee, &vd, element, foreign, false); break; case BASE_TYPE_RECORD: case BASE_TYPE_ARRAY: this->setArgByBasePointerToTemporary( callee, vd, element, foreign); break; default: // must not happen assert(false); } break; case ValDeclaration::OBJ_CLASS_VARIABLE: switch (element.actual->baseType) { case BASE_TYPE_INTEGER: case BASE_TYPE_ENUM: case BASE_TYPE_REAL: switch (vd.mode) { case ValDeclaration::MODE_IN: op = this->setArgByValue( callee, &vd, element, foreign, false); assert(op == NULL); break; case ValDeclaration::MODE_INOUT: case ValDeclaration::MODE_OUT: // need to copy back to op. op = this->setArgByValue( callee, &vd, element, foreign, true); assert(op != NULL); break; } break; case BASE_TYPE_RECORD: case BASE_TYPE_ARRAY: this->setArgByBasePointer( callee, &vd, element, foreign); break; default: // must not happen assert(false); } break; case ValDeclaration::OBJ_CLASS_SIGNAL: switch (element.actual->baseType) { case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: switch (vd.mode) { case ValDeclaration::MODE_IN: this->setArgByBasePointer( callee, &vd, element, foreign); break; case ValDeclaration::MODE_INOUT: this->setArgByBasePointer( callee, &vd, element, foreign); /* fall through */ case ValDeclaration::MODE_OUT: this->setArgByDriver( callee, c.drivers, vd, element, foreign, true); break; } break; case BASE_TYPE_INTEGER: case BASE_TYPE_ENUM: case BASE_TYPE_REAL: switch (vd.mode) { case ValDeclaration::MODE_IN: this->setArgByPointer( callee, &vd, element, foreign); break; case ValDeclaration::MODE_INOUT: this->setArgByPointer( callee, &vd, element, foreign); /* fall through */ case ValDeclaration::MODE_OUT: this->setArgByDriver( callee, c.drivers, vd, element, foreign, false); break; } break; default: assert(0); } break; default: // must not happen assert(false); } this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); return op; } OpCode * GenCode::setArgByValue( Reference *callee, const ValDeclaration *vd, AssociationElement &element, const char *foreign, bool copyBack ) { Expression *act = element.actual; if (act == NULL) { act = element.hiddenFormal; } assert(act != NULL); // sanity check switch (act->baseType) { case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: case BASE_TYPE_ENUM: break; default: // composites must be called by reference! std::cerr << "hm....? act=" << act << ", formal=" << element.formal << std::endl; assert(false); case BASE_TYPE_UNSET: assert(false); } if (vd != NULL) { assert(element.formal == NULL); // FIXME } else { // FIXME individual association SimpleName *sn = dynamic_cast(element.formal); assert(sn != NULL); vd = dynamic_cast(sn->getDeclaration()); assert(vd != NULL); } act->accept(*this); Reference *formal; if (foreign != NULL) { formal = new Reference(*vd->name); } else { formal = new Reference(vd->getICName()); } Operand *value = this->sourceRegs.getValue(act->baseType); SetParam *sp = new SetParam(value, callee, formal); this->container->addCode(sp); if (foreign != NULL) { sp->annotate("foreign", foreign); GenCode::annotateSetParamType(*sp, *vd); } if (copyBack) { Operand *dest = this->sourceRegs.getDestination( act->baseType); GetParam *gp = new GetParam(formal, callee, dest); return gp; } return NULL; } void GenCode::setArgByBasePointer( Reference *callee, const ValDeclaration *vd, AssociationElement &element, const char *foreign ) { if (vd == NULL) { assert(element.formal != NULL); // FIXME SimpleName *sn = dynamic_cast(element.formal); assert(sn != NULL); vd = dynamic_cast(sn->getDeclaration()); assert(vd != NULL); } Expression *act = element.actual; if (act == NULL) { act = element.hiddenFormal; } assert(act != NULL); act->accept(*this); std::string formal_name; if (foreign != NULL) { formal_name = *vd->name; } else { formal_name = vd->getICName(); } Reference *formal = new Reference(formal_name); Operand *pointer = this->sourceRegs.getPointer(); SetParam *sp = new SetParam(pointer, callee, formal); this->container->addCode(sp); if (foreign != NULL) { sp->annotate("foreign", foreign); GenCode::annotateSetParamType(*sp, *vd); } if (vd->isUnconstraint()) { if (this->sourceRegs.isUnconstraint()) { // either constraints are paremeters already this->setConstraintsByRS(callee, formal_name, foreign); } else { // or the array is constraint this->setConstraintsByType(callee, formal_name, act->type, foreign); } } } void GenCode::setArgByBasePointerToTemporary( Reference *callee, const ValDeclaration &vd, AssociationElement &element, const char *foreign ) { assert(element.hiddenFormal != NULL); // assign the constant to the hidden formal this->assignExpression = false; this->isTarget = true; element.hiddenFormal->accept(*this); this->destRegs = this->sourceRegs; this->sourceRegs = RegisterSet(*this->container); this->isTarget = false; this->assignExpression = true; element.actual->accept(*this); this->assignExpression = false; // get a grip on the hidden formal this->sourceRegs = RegisterSet(*this->container); element.hiddenFormal->accept(*this); std::string formal_name; if (foreign != NULL) { formal_name = *vd.name; } else { formal_name = vd.getICName(); } Reference *formal = new Reference(formal_name); SetParam *sp = new SetParam(this->sourceRegs.getPointer(), callee, formal); this->container->addCode(sp); if (foreign != NULL) { sp->annotate("foreign", foreign); GenCode::annotateSetParamType(*sp, vd); } if (vd.isUnconstraint()) { if (this->sourceRegs.isUnconstraint()) { // either constraints are paremeters already this->setConstraintsByRS(callee, formal_name, foreign); } else { // or the array is constraint this->setConstraintsByType(callee, formal_name, element.actual->type, foreign); } } } void GenCode::setArgByPointer( Reference *callee, const ValDeclaration *vd, AssociationElement &element, const char *foreign ) { if (vd == NULL) { assert(element.formal != NULL); // FIXME SimpleName *sn = dynamic_cast(element.formal); assert(sn != NULL); vd = dynamic_cast(sn->getDeclaration()); assert(vd != NULL); } Expression *act = element.actual; if (act == NULL) { act = element.hiddenFormal; } assert(act != NULL); act->accept(*this); Reference *formal; if (foreign != NULL) { formal = new Reference(*vd->name); } else { formal = new Reference(vd->getICName()); } Operand *pointer = this->sourceRegs.getDestination(act->baseType); SetParam *sp = new SetParam(pointer, callee, formal); this->container->addCode(sp); if (foreign != NULL) { sp->annotate("foreign", foreign); GenCode::annotateSetParamType(*sp, *vd); } } void GenCode::setArgByDriver( Reference *callee, const std::list &drivers, const ValDeclaration &vd, AssociationElement &element, const char *foreign, bool usePointer ) { assert(element.formal == NULL); // need a driver this->isTarget = true; element.actual->accept(*this); this->isTarget = false; std::string name; bool found = false; for (std::list::const_iterator i = drivers.begin(); i != drivers.end(); i++) { if (&(*i)->signal == &vd) { if (foreign != NULL) { name = (*i)->getForeignName(); } else { name = (*i)->getICName(); } found = true; break; } } assert(found); Reference *formal = new Reference(name); Operand *drv; if (usePointer) { drv = this->sourceRegs.getPointer(); } else { drv = this->sourceRegs.getDestination( element.actual->baseType); } SetParam *sp = new SetParam(drv, callee, formal); this->container->addCode(sp); if (foreign != NULL) { sp->annotate("foreign", foreign); } } void GenCode::annotateSetParamType( SetParam &sp, const ValDeclaration &vd ) { const TypeDeclaration *t = ResolveTypes::findBaseType(vd.subtypeIndic); switch (vd.subtypeIndic->baseType) { case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: case BASE_TYPE_RECORD: case BASE_TYPE_ENUM: // cannot be an anonymous type, and doesn't need constraints assert(t->name != NULL); sp.annotate("type", *t->name); sp.annotate("array", 0); return; case BASE_TYPE_ARRAY: sp.annotate("array", 1); break; default: // must not happen assert(false); } // case: array const UnconstrainedArrayType *ua = dynamic_cast(t); assert(ua != NULL); assert(ua->elementType != NULL); // FIXME doesn't exactly match with GCTypes... t = ResolveTypes::findBaseType(ua->elementType); sp.annotate("type", *t->name); // only valid for foreign SetParams! if (vd.isUnconstraint()) { sp.annotate("unconstraint", 1); } else { sp.annotate("unconstraint", 0); // FIXME bounds somewhere? } } void GenCode::setConstraintsByType( Reference *cRef, const std::string &icPrefix, const TypeDeclaration *t, const char *foreign ) { std::list ic = std::list(); ResolveTypes::pickupIndexConstraint(t, ic); assert(! ic.empty()); size_t dim = 0; for (std::list::const_iterator i = ic.begin(); i != ic.end(); i++, dim++) { ImmediateOperand *lb = new ImmediateOperand((*i)->getLeftBound()); ImmediateOperand *rb = new ImmediateOperand((*i)->getRightBound()); ImmediateOperand *db = new ImmediateOperand((*i)->getDirection()); Reference *lname = new Reference(icPrefix + "_lb_" + util::MiscUtil::toString(dim)); Reference *rname = new Reference(icPrefix + "_rb_" + util::MiscUtil::toString(dim)); Reference *dirname = new Reference(icPrefix + "_dir_" + util::MiscUtil::toString(dim)); SetParam *sp1 = new SetParam(lb, cRef, lname); SetParam *sp2 = new SetParam(rb, cRef, rname); SetParam *sp3 = new SetParam(db, cRef, dirname); this->container->addCode(sp1); this->container->addCode(sp2); this->container->addCode(sp3); if (foreign != NULL) { sp1->annotate("foreign", foreign); sp2->annotate("foreign", foreign); sp3->annotate("foreign", foreign); sp1->annotate("bounds", "l"); sp2->annotate("bounds", "r"); sp3->annotate("bounds", "dir"); sp1->annotate("array", 1); sp2->annotate("array", 1); sp3->annotate("array", 1); sp1->annotate("unconstraint", 1); sp2->annotate("unconstraint", 1); sp3->annotate("unconstraint", 1); } } } void GenCode::setConstraintsByRS( Reference *cRef, const std::string &icPrefix, const char *foreign ) { std::list lb; std::list rb; std::list dirs; this->sourceRegs.getConstraints(lb, rb, dirs); std::list::const_iterator li = lb.begin(); std::list::const_iterator ri = rb.begin(); std::list::const_iterator di = dirs.begin(); assert(lb.size() == dirs.size()); for (size_t dim = 0; li != lb.end(); li++, ri++, di++, dim++) { Reference *lname = new Reference(icPrefix + "_lb_" + util::MiscUtil::toString(dim)); Reference *rname = new Reference(icPrefix + "_rb_" + util::MiscUtil::toString(dim)); Reference *dirname = new Reference(icPrefix + "_dir_" + util::MiscUtil::toString(dim)); SetParam *sp1 = new SetParam(*li, cRef, lname); SetParam *sp2 = new SetParam(*ri, cRef, rname); SetParam *sp3 = new SetParam(*di, cRef, dirname); this->container->addCode(sp1); this->container->addCode(sp2); this->container->addCode(sp3); if (foreign != NULL) { sp1->annotate("foreign", foreign); sp1->annotate("bounds", "l"); sp2->annotate("foreign", foreign); sp2->annotate("bounds", "r"); sp3->annotate("foreign", foreign); sp3->annotate("bounds", "dir"); sp1->annotate("array", 1); sp2->annotate("array", 1); sp3->annotate("array", 1); sp1->annotate("unconstraint", 1); sp2->annotate("unconstraint", 1); sp3->annotate("unconstraint", 1); } } } void GenCode::addUnconstraintParams(const ValDeclaration &node) { const UnconstrainedArrayType *ua = dynamic_cast( ResolveTypes::findBaseType(node.subtypeIndic)); assert(ua != NULL); std::string prefix = node.getICName(); for (size_t dim = 0; dim < ua->numIndices; dim++) { // make a NULL range the default std::list lIv = std::list(); std::list rIv = std::list(); std::list dIv = std::list(); lIv.push_back(ImmediateOperand::getOne()); rIv.push_back(ImmediateOperand::getZero()); dIv.push_back(ImmediateOperand::getOne()); TypeElement *ltypeE = new TypeElement("universal_integer", lIv); TypeElement *rtypeE = new TypeElement("universal_integer", rIv); TypeElement *dtypeE = new TypeElement("universal_integer", dIv); std::string lname = prefix + "_lb_" + util::MiscUtil::toString(dim); std::string rname = prefix + "_rb_" + util::MiscUtil::toString(dim); std::string dirname = prefix + "_dir_" + util::MiscUtil::toString(dim); Data *ld = new Data(lname, STORAGE_TYPE_VARIABLE, ltypeE, NULL); Data *rd = new Data(rname, STORAGE_TYPE_VARIABLE, rtypeE, NULL); Data *dd = new Data(dirname, STORAGE_TYPE_VARIABLE, dtypeE, NULL); this->container->addData(ld); this->container->addData(rd); this->container->addData(dd); } } void GenCode::getConstraints(const ValDeclaration &node) { const UnconstrainedArrayType *ua = dynamic_cast( ResolveTypes::findBaseType(node.subtypeIndic)); assert(ua != NULL); std::string prefix = node.getICName(); std::list lbs; std::list rbs; std::list dirs; for (size_t dim = 0; dim < ua->numIndices; dim++) { std::string lname = prefix + "_lb_" + util::MiscUtil::toString(dim); std::string rname = prefix + "_rb_" + util::MiscUtil::toString(dim); std::string dirname = prefix + "_dir_" + util::MiscUtil::toString(dim); Register *lb = this->container->createRegister(OP_TYPE_POINTER); Register *rb = this->container->createRegister(OP_TYPE_POINTER); Register *dir = this->container->createRegister(OP_TYPE_POINTER); Mov *lm = new Mov(new Reference(lname), lb); Mov *rm = new Mov(new Reference(rname), rb); Mov *dm = new Mov(new Reference(dirname), dir); this->container->addCode(lm); this->container->addCode(rm); this->container->addCode(dm); IndirectOperand *lbv = new IndirectOperand(lb, OP_TYPE_INTEGER); IndirectOperand *rbv = new IndirectOperand(rb, OP_TYPE_INTEGER); IndirectOperand *dbv = new IndirectOperand(dir, OP_TYPE_INTEGER); lbs.push_back(lbv); rbs.push_back(rbv); dirs.push_back(dbv); } this->sourceRegs.setUnconstraintBounds(lbs, rbs, dirs); } void GenCode::handleCompositeReturn(FunctionCall &node) { assert(false); /* TODO */ } void GenCode::annotateDataSize(Data &data, const SubtypeIndication *type) { const TypeDeclaration *t = ResolveTypes::findBaseType(type); const EnumerationType *et = dynamic_cast(t); // consider only enumeration types if (et == NULL) { // also consider one-dimensional arrays const UnconstrainedArrayType *ua = dynamic_cast(t); if (ua == NULL) { return; } t = ResolveTypes::findBaseType(ua->elementType); et = dynamic_cast(t); if (et == NULL) { return; } } assert(et->elements != NULL); size_t sz = et->elements->size(); double bit_count = log(static_cast(sz)) / log(2.0); int cnt = static_cast(ceil(bit_count)); data.annotate("display_size", cnt); data.annotate("display", *et->name); } void GenCode::visit(AttributeSpecification &node) { //TODO } void GenCode::processAlternative( CaseAlternative &node, Operand *cmpVal, Label *caseNext, Label *caseOut ) { assert(node.isVals != NULL); assert(node.thenStats != NULL); Label *altFound = LabelFactory::getLabel("alternative_execute"); for (std::list::const_iterator i = node.isVals->begin(); i != node.isVals->end(); i++) { const Others *others = dynamic_cast(*i); if (others != NULL) { Jmp *jmp = new Jmp(altFound); this->container->addCode(jmp); break; } this->assignExpression = false; this->isTarget = false; this->sourceRegs = RegisterSet(*this->container); (*i)->accept(*this); Operand *choice = this->sourceRegs.getValue((*i)->baseType); Je *je = new Je(cmpVal, choice, altFound); this->container->addCode(je); } Jmp *jmp = new Jmp(caseNext); this->container->addCode(jmp); this->container->addCode(altFound); this->sourceRegs = RegisterSet(*this->container); this->listTraverse(*node.thenStats); Jmp *jmp2 = new Jmp(caseOut); this->container->addCode(jmp2); } void GenCode::visit(CaseStat &node) { // TODO: there are a number of restrictions on // select and alternatives, which aren't checked yet // see lrm 8.8 for details. // However these restrictions should be checked elsewhere. // // TODO 2: This is a pretty poor implementation, as all // expression choices should be locally static. // A good implementation would choose the best algorithm // for the alternatives, including // - a jump lookup table // - if/then/else constructs (that's done here) // - a combination thereof // - ... assert(node.select != NULL); assert(node.alternatives != NULL); this->assignExpression = false; this->isTarget = false; this->sourceRegs = RegisterSet(*this->container); this->destRegs = RegisterSet(*this->container); switch (node.select->baseType) { case BASE_TYPE_RECORD: case BASE_TYPE_ARRAY: // FIXME not handled yet: this needs to // 1) assign the result of the expression to a temporary // 2) compare the temporary with the choices assert(false); break; case BASE_TYPE_UNSET: assert(false); break; default: break; } node.select->accept(*this); Operand *cmpVal = this->sourceRegs.getValue(node.select->baseType); this->sourceRegs = RegisterSet(*this->container); Label *caseOut = LabelFactory::getLabel("case_out"); // handle each alternative for (std::list::const_iterator i = node.alternatives->begin(); i != node.alternatives->end(); /* nothing */) { CaseAlternative *current = *i; Label *caseNext = caseOut; i++; // use caseOut as last next label. if (i != node.alternatives->end()) { caseNext = LabelFactory::getLabel("case_next"); } this->processAlternative(*current, cmpVal, caseNext, caseOut); if (i != node.alternatives->end()) { this->container->addCode(caseNext); } } this->container->addCode(caseOut); } /* * ================== ASSIGN VISITOR ==================== */ void GenCode::AssignVisitor::visit(SubtypeIndication &node) { // traverse to the defining type. assert(node.declaration != NULL); switch (node.baseType) { case BASE_TYPE_ENUM: case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: { /* traverse to declaration */ TypeDeclaration *parent = const_cast(node.declaration); parent->accept(*this); return; } case BASE_TYPE_RECORD: /* subtype of a record cannot happen */ assert(false); break; case BASE_TYPE_ARRAY: this->processArraySubtype(node); break; default: /* must not happen */ assert(false); break; } } void GenCode::AssignVisitor::processArraySubtype(SubtypeIndication &node) { // FIXME slices // FIXME unconstraint lbounds/ubounds class ArrayAssign : public ArrayIterate { public: ArrayAssign( TypeDeclaration *at, intermediate::CodeContainer &container, AssignVisitor &instance, std::list unclbounds, std::list uncubounds, std::list undirects ) : ArrayIterate(at, instance.src->getPointer(), container, unclbounds, uncubounds, undirects), av(instance) {} private: // cppcheck-suppress unusedPrivateFunction (false positive) virtual void iterateBody( Register *element, std::list idcs ) { RegisterSet *old_src = this->av.src; RegisterSet *old_dst = this->av.dst; this->av.src = new RegisterSet(this->cc); if (this->av.dst != NULL) { this->av.dst = new RegisterSet(*this->av.dst); this->setDest(idcs); } this->av.src->isSignal = old_src->isSignal; this->av.src->setPointer(element); switch (this->elementType->baseType) { case BASE_TYPE_RECORD: this->elementType->accept(this->av); break; case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: case BASE_TYPE_ENUM: this->av.performOperation( this->elementType->baseType); break; default: /* must not happen */ assert(false); break; } delete this->av.src; if (this->av.dst != NULL) { delete this->av.dst; } this->av.src = old_src; this->av.dst = old_dst; } void setDest(std::list idcs) { assert(this->av.dst != NULL); std::list idx = std::list(); for (std::list::const_iterator i = idcs.begin(); i != idcs.end(); i++) { idx.push_back(*i); } this->av.dst->subscribe(this->arrayType, idx); } AssignVisitor &av; }; std::list lb; std::list ub; std::list ds; this->src->getConstraints(lb, ub, ds); if (this->dst != NULL) { // perform subtype conversion on the fly for unconstraint // arrays. // FIXME where bounds are statically known, subtype conversion // must have taken place beforehand! // // FIXME this still leaves the problem of unconstraint <-> // constraint // // FIXME actually src should take over the constraints of // dest, but that doesn't matter that much imho if (this->dst->isUnconstraint()) { if (this->src->isUnconstraint()) { this->dst->setUnconstraintBounds(lb, ub, ds); } else { assert(false); } } } ArrayAssign aa = ArrayAssign(&node, this->container, *this, lb, ub, ds); aa.iterate(); } void GenCode::AssignVisitor::visit(UnconstrainedArrayType &node) { // mustn't traverse to UnconstrainedArrayType, should be handled from // elsewhere already // FIXME: eventually unconstrained arrays as parameters of subprograms // might bring us here. assert(false); } void GenCode::AssignVisitor::visit(RecordType &node) { universal_integer relement = 0; for (std::list::const_iterator i = node.elements->begin(); i != node.elements->end(); i++) { (*i)->accept(*this); Operand *src_composite = this->src->getPointer(); Operand *dst_composite = NULL; if (this->dst != NULL) { dst_composite = this->dst->getPointer(); } // calculate new record offset of source relement++; Register *nb1 = this->container.createRegister(OP_TYPE_POINTER); ImmediateOperand *off1 = new ImmediateOperand(relement); Type *rt1 = TypeFactory::lookupType(node.getICName()); assert(rt1 != NULL); ROffset *roffOp1 = new ROffset(this->src->getPointer(), off1, rt1, nb1); this->container.addCode(roffOp1); this->src->setPointer(nb1); // and for destination if (this->dst != NULL) { Register *nb2 = this->container.createRegister( OP_TYPE_POINTER); ImmediateOperand *off2 = new ImmediateOperand(relement); Type *rt2 = TypeFactory::lookupType(node.getICName()); assert(rt2 != NULL); ROffset *roffOp2 = new ROffset( this->dst->getPointer(), off2, rt2, nb2); this->container.addCode(roffOp2); this->dst->setPointer(nb2); } // traverse to element (*i)->accept(*this); // restore old base pointers this->src->setPointer(src_composite); if (this->dst != NULL) { this->dst->setPointer(dst_composite); } } } void GenCode::AssignVisitor::visit(RecordTypeElement &node) { node.subtype->accept(*this); } void GenCode::AssignVisitor::visit(RangeConstraintType &node) { this->performOperation(node.baseType); } void GenCode::AssignVisitor::visit(PhysicalType &node) { this->performOperation(BASE_TYPE_INTEGER); } void GenCode::AssignVisitor::visit(EnumerationType &node) { this->performOperation(BASE_TYPE_INTEGER); } void GenCode::AssignVisitor::performOperation(enum BaseType t) { switch (this->operation) { case ASSIGN_OPERATION_COPY: this->makeAssignment(t); break; case ASSIGN_OPERATION_LOG: this->logValue(); break; case ASSIGN_OPERATION_CONNECT: this->connect(); break; case ASSIGN_OPERATION_WAKEON: this->wakeon(t); break; } } void GenCode::AssignVisitor::makeAssignment(enum BaseType t) { Operand *so = this->src->getValue(t); assert(this->dst != NULL); Operand *dsto = this->dst->getDestination(t); OpCode *assign; if (this->dst->isSignal) { assert(this->dataOp != NULL); assign = new Update(so, this->dataOp, dsto); } else { assign = new Mov(so, dsto); } this->container.addCode(assign); } void GenCode::AssignVisitor::logValue(void) { assert(this->dataOp != NULL); Operand *c = this->src->getValue(BASE_TYPE_INTEGER); Log *l = new Log(this->dataOp, c); this->container.addCode(l); } void GenCode::AssignVisitor::wakeon(enum BaseType t) { Operand *sigPtr = this->src->getDestination(t); WakeOn *wo = new WakeOn(sigPtr); this->container.addCode(wo); } void GenCode::AssignVisitor::connect(void) { assert(this->dataOp == NULL); assert(this->dst->isSignal); // hm... getDestination ignores the base type if is a signal. Connect *c = new Connect(this->dst->getDestination(BASE_TYPE_REAL), this->src->getDestination(BASE_TYPE_REAL)); this->container.addCode(c); } /* * ================== PROCESS STACKED EXPRESSION =============== */ GenCode::ProcessStackedExpression::ProcessStackedExpression( GenCode &gc, Expression &n ): genCode(gc), node(n), stackedAssignExpression(gc.assignExpression) { gc.assignExpression = false; } GenCode::ProcessStackedExpression::~ProcessStackedExpression() { this->genCode.assignExpression = this->stackedAssignExpression; if (this->stackedAssignExpression) { this->genCode.processExpression(node); } } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/ConstantPropagation.hpp0000664000175000017500000001522311263120602023022 0ustar potyrapotyra/* $Id: ConstantPropagation.hpp 4810 2009-10-07 14:11:14Z potyra $ * ConstantPropagation: propagate results of constant expressions. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONSTANT_PROPAGATION_HPP_INCLUDED #define __CONSTANT_PROPAGATION_HPP_INCLUDED #include #include "frontend/visitor/TopDownVisitor.hpp" #include "frontend/ast/Types.hpp" namespace ast { //! evaluate constant expressions and propagate constant values. /** @todo * set nodes for * - index expressions * - slices * - ranges * - initializer expressions * - if conditions * - assign statements * - etc. * * propagate constants in a process/function * * what else? */ class ConstantPropagation : public TopDownVisitor { public: ConstantPropagation(); private: /** visit a ConstInteger * @param node node that get's visited. */ virtual void visit(ConstInteger &node); /** visit a ConstReal * @param node node that get's visited. */ virtual void visit(ConstReal &node); /** visit a FunctionCall * @param node node that get's visited. */ virtual void visit(FunctionCall &node); /** Visit a VarAssignStat * @param node VarAssignStat node that get's visited. */ virtual void visit(VarAssignStat &node); /** Visit a SigAssignStat * @param node SigAssignStat node that get's visited. */ virtual void visit(SigAssignStat &node); /** visit a WaveFormElem * @param node node that get's visited. */ virtual void visit(WaveFormElem &node); /** Visit a WhileLoopStat * @param node WhileLoopStat node that get's visited. */ virtual void visit(WhileLoopStat &node); /** Visit a Subscript node. * @param node Subscript node that get's visited. */ virtual void visit(Subscript &node); /** Visit a Slice node. * @param node Slice node that get's visited. */ virtual void visit(Slice &node); /** Visit a TypeConversion node. * @param node TypeConversion node that get's visited. */ virtual void visit(TypeConversion &node); /** Visit a SimpleName node. * @param node SimpleName node that get's visited. */ virtual void visit(SimpleName &node); /** Visit a SelectedName node. * @param node SelectedName node that get's visited. */ virtual void visit(SelectedName &node); /** Visit an AttributeName node. * @param node AttributeName node that get's visited. */ virtual void visit(AttributeName &node); /** visit a TemporaryName * @param node node that get's visited. */ virtual void visit(TemporaryName &node); /** Visit a WaitStat * @param node WaitStat node that get's visited. */ virtual void visit(WaitStat &node); /** Visit a ReturnStat * @param node ReturnStat node that get's visited. */ virtual void visit(ReturnStat &node); /** Visit a AssertStat * @param node AssertStat node that get's visited. */ virtual void visit(AssertStat &node); /** Visit a DiscreteRange * @param node DiscreteRange node that get's visited. */ virtual void visit(DiscreteRange &node); /** Visit a CaseStat * @param node CaseStat node that get's visited. */ virtual void visit(CaseStat &node); /** Visit a CaseAlternative * @param node CaseAlternative node that get's visited. */ virtual void visit(CaseAlternative& node); /** Visit an Aggregate * @param node Aggregate node that get's visited. */ virtual void visit(Aggregate &node); /** Visit an AttributeSpecification node. * @param node AttributeSpecification node that gets visited. */ virtual void visit(AttributeSpecification &node); /** Visit a AssociationElement node. * @param node AssociationElement node that get's visited. */ virtual void visit(AssociationElement &node); //! Process a generic AstNode. /** This function will get called for each AstNode * that get's visited. * * @param node AstNode */ virtual void process(AstNode &node); //! Process a generic ValDeclaration. /** This function will get called for each ValDeclaration (or class * derived from ValDeclaration) that get's visited. * * @param node ValDeclaration instance. */ virtual void process(ValDeclaration &node); //! Process a generic ConditionedStat. /** This function will get called for each ConditionedStat (or class * derived from ConditionedStat) that get's visited. * * @param node ConditionedStat instance. */ virtual void process(ConditionedStat &node); //! try to reduce a builtin function call to a constant node. /** @param node FunctionCall with a builtin definition. * @param args constant positional parameter list. */ void optimizeBuiltin(FunctionCall &node, std::list args); //! set node to the replacement in ConstValue /** @param node: reference to pointer to node, that should get * replaced. * @return true: if node is afterwards const (or was const before). */ bool setNode(Expression *&node) const; /** reset constValue */ void reset(void); /** traverse (and optimize) a list of expressions * @param l list of Expressions to optimize. Will do nothing, if * l is NULL. * @return true if all of the list were constants, false otherwise * (also false if the list is NULL). */ bool listOptimize(std::list *l); /** determine the corresponding ElementAssociation for an index * position. RangeSet's (via ResolveAggregates) must have been * set before. * @param index index position. * @param node corresponding aggregate * @return corresponding ElementAssociation, or NULL if not * found/error. */ ElementAssociation * findAggregateAssoc(universal_integer index, Aggregate &node) const; /** generate a constraint array type for a ConstArray. * @param haveType needed base type (may be constraint already) * @param numElems number of array elements * @return if haveType is already constraint, returns haveType. * Otherwise, a new constraint type is created, which * is constraint from 0 to elements - 1. The former * implicitely creates a subtype conversion. */ static TypeDeclaration * makeCAType(TypeDeclaration *haveType, size_t numElems); /** either the picked up constant, or NULL */ Expression *constValue; }; }; /* namespace ast */ #endif /* __CONSTANT_PROPAGATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/NormalizeAssocLists.cpp0000664000175000017500000002403011212175426022774 0ustar potyrapotyra/* $Id: NormalizeAssocLists.cpp 4534 2009-06-05 11:01:42Z potyra $ * * Normalize association lists. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/NormalizeAssocLists.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/LibraryList.hpp" #include "frontend/ast/Library.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/ast/NodeFactory.hpp" #include #include namespace ast { void NormalizeAssocLists::visit(CompInstStat &node) { assert(node.entity != NULL); assert(node.entity->ports != NULL); assert(node.entity->generics != NULL); assert(node.entity->region != NULL); this->formals = *NodeFactory::listCast(node.entity->ports); this->positional = true; this->pos = 0; this->region = node.entity->region; if (node.portMap != NULL) { this->listTraverse(*node.portMap); this->addMissingPortAssocs(node); /* sort port map by position */ std::vector v; v.insert(v.begin(), node.portMap->begin(), node.portMap->end()); std::sort(v.begin(), v.end(), NormalizeAssocLists::sortPosPred); node.portMap->clear(); node.portMap->insert(node.portMap->begin(), v.begin(), v.end()); } this->formals.clear(); this->formals = *NodeFactory::listCast( node.entity->generics); this->positional = true; this->pos = 0; if (node.genericMap != NULL) { this->listTraverse(*node.genericMap); this->addMissingGenericAssocs(node); /* sort generic map by position */ std::vector v; v.insert(v.begin(), node.genericMap->begin(), node.genericMap->end()); std::sort(v.begin(), v.end(), NormalizeAssocLists::sortPosPred); node.genericMap->clear(); node.genericMap->insert(node.genericMap->begin(), v.begin(), v.end()); } this->formals.clear(); this->region = NULL; } void NormalizeAssocLists::visit(AssociationElement &node) { if (node.formal == NULL) { if (! this->positional) { CompileError *ce = new CompileError(node, "Positional association " "used after named association."); ErrorRegistry::addError(ce); return; } if (this->formals.empty()) { CompileError *ce = new CompileError(node, "Cannot associate positional " "association (too many arguments?)."); ErrorRegistry::addError(ce); return; } // register SimpleName as formal assert(this->region != NULL); const ValDeclaration *formal = this->formals.front(); SimpleName *sn = NormalizeAssocLists::makeNameOfVal( formal, this->region, node.location); node.formal = sn; this->formals.pop_front(); node.pos = this->pos; this->pos++; return; } // named association this->positional = false; this->pickedUpVal = NULL; node.formal->accept(*this); assert(this->pickedUpVal != NULL); node.pos = this->findAndRemove(this->pickedUpVal, node.location); this->pickedUpVal = NULL; } void NormalizeAssocLists::visit(SimpleName &node) { const SymbolDeclaration *decl = node.getDeclaration(); const ValDeclaration *sig = dynamic_cast(decl); if (sig == NULL) { assert(decl != NULL); std::string msg = "AssociationElement <"; msg += util::MiscUtil::toString(node); msg += "> refers to <"; msg += util::MiscUtil::toString(decl->location); msg += ": "; msg += util::MiscUtil::toString(*decl); msg += ">, which is not an object declaration."; CompileError *ce = new CompileError(node, msg); // bail out immediately, algorithm might otherwise // break elsewhere throw(*ce); } assert(sig != NULL); this->pickedUpVal = sig; } void NormalizeAssocLists::visit(TemporaryName &node) { CompileError *ce = new CompileError(node, "Cannot use temporary names in " "associations."); ErrorRegistry::addError(ce); } void NormalizeAssocLists::visit(SelectedName &node) { // FIXME individual association currently unsupported. assert(false); } void NormalizeAssocLists::visit(AttributeName &node) { CompileError *ce = new CompileError(node, "Cannot use attributes in port " "associations."); ErrorRegistry::addError(ce); } void NormalizeAssocLists::visit(Architecture &node) { /* traverse to concurrentStats */ this->arch = &node; if (node.concurrentStats != NULL) { this->listTraverse(*node.concurrentStats); } this->arch = NULL; } void NormalizeAssocLists::visit(Library& node) { this->listTraverse(node.units); } void NormalizeAssocLists::visit(LibraryList& node) { this->listTraverse(node.libraries); } int NormalizeAssocLists::findAndRemove( const ValDeclaration *val, Location errLoc ) { int p = this->pos; for (std::list::iterator i = this->formals.begin(); i != this->formals.end(); i++, p++) { if ((*i) == val) { this->formals.erase(i); return p; } } std::string msg = "Error in association: <"; msg += *(val->name); msg += "> already associated."; CompileError *ce = new CompileError(errLoc, msg); ErrorRegistry::addError(ce); return -1; } template void NormalizeAssocLists::addMissingAssocs( CompInstStat &node, std::list &unassociated, const char *kind, enum symType symbolType, std::list &mapList ) { while (! unassociated.empty()) { ValDeclaration *formal = unassociated.front(); this->addMissingAssoc( node.location, *formal, kind, symbolType, mapList); unassociated.pop_front(); } } template void NormalizeAssocLists::addMissingAssoc( const Location &loc, ValDeclaration &formal, const char *kind, enum symType symbolType, std::list &mapList ) { switch (formal.mode) { case ValDeclaration::MODE_IN: // must have initializer (LRM 1.1.1.2) if (formal.init == NULL) { std::string msg = std::string("Must associate "); msg += kind; msg += " <"; msg += *formal.name; msg += "> which has mode IN but no "; msg += "initializer."; CompileError *ce = new CompileError(loc, msg); ErrorRegistry::addError(ce); return; } break; case ValDeclaration::MODE_OUT: case ValDeclaration::MODE_INOUT: // ok break; } // make excplicit association with an implicit std::string *n = new std::string(*(formal.name)); (*n) += "__hidden__"; (*n) += util::MiscUtil::toString(this->hiddenCounter); T *hiddenActual = NormalizeAssocLists::createVal( n, formal.mode, formal.init, formal.subtypeIndic, loc); if (hiddenActual->isUnconstraint()) { if (formal.init == NULL) { std::string msg = "Must associate "; msg += kind; msg += " <"; msg += *formal.name; msg += "> which is an unconstraint "; msg += "array but has no initializer."; CompileError *ce = new CompileError(loc, msg); ErrorRegistry::addError(ce); return; } SubtypeIndication *actualInferredType = dynamic_cast(formal.init->type); assert(actualInferredType != NULL); hiddenActual->subtypeIndic = actualInferredType; } assert(this->arch != NULL); assert(this->arch->declarations != NULL); assert(this->arch->region != NULL); assert(this->region != NULL); this->arch->declarations->push_back(hiddenActual); Symbol *sym = new Symbol(n, symbolType, NULL, *hiddenActual); this->arch->region->registerSymbol(sym); SimpleName *formalN = NormalizeAssocLists::makeNameOfVal( &formal, this->region, loc); AssociationElement *elem = new AssociationElement( formalN, NULL, loc); SimpleName *hiddenFormalN = NormalizeAssocLists::makeNameOfVal( hiddenActual, this->arch->region, loc); elem->hiddenFormal = hiddenFormalN; formalN->baseType = formal.subtypeIndic->baseType; hiddenFormalN->baseType = formal.subtypeIndic->baseType; mapList.push_back(elem); this->hiddenCounter++; } template T * NormalizeAssocLists::createVal( std::string *name, enum ValDeclaration::Mode pMode, Expression *varInit, SubtypeIndication *si, Location loc ) { assert(false); return NULL; } template <> SignalDeclaration * NormalizeAssocLists::createVal( std::string *name, enum ValDeclaration::Mode pMode, Expression *varInit, SubtypeIndication *si, Location loc ) { return new SignalDeclaration( name, pMode, false, varInit, si, loc); } template <> ConstantDeclaration * NormalizeAssocLists::createVal( std::string *name, enum ValDeclaration::Mode pMode, Expression *varInit, SubtypeIndication *si, Location loc ) { return new ConstantDeclaration( name, varInit, si, false, // FIXME? loc); } void NormalizeAssocLists::addMissingPortAssocs(CompInstStat &node) { assert(node.portMap != NULL); this->addMissingAssocs( node, this->formals, "port", SYMBOL_SIGNAL, *node.portMap); } void NormalizeAssocLists::addMissingGenericAssocs(CompInstStat &node) { assert(node.genericMap != NULL); this->addMissingAssocs( node, this->formals, "generic", SYMBOL_VARIABLE, *node.genericMap); } bool NormalizeAssocLists::sortPosPred( AssociationElement *l, AssociationElement *r ) { return l->pos < r->pos; } SimpleName * NormalizeAssocLists::makeNameOfVal( const ValDeclaration *val, const DeclarativeRegion *lookupRegion, Location loc ) { std::list formalCands = lookupRegion->lookupLocal(*val->name); assert(formalCands.size() == 1); SimpleName *sn = new SimpleName(new std::string(*val->name), formalCands, loc); sn->type = val->subtypeIndic; sn->baseType = val->subtypeIndic->baseType; return sn; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/GCTypes.hpp0000664000175000017500000001332511164163115020352 0ustar potyrapotyra/* $Id: GCTypes.hpp 4443 2009-03-30 15:33:33Z potyra $ * * Generate intermediate code, related to type handling. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GC_TYPES_HPP_INCLUDED #define __GC_TYPES_HPP_INCLUDED #include #include #include "frontend/visitor/NullVisitor.hpp" #include "intermediate/container/TypeElement.hpp" namespace ast { //! intermediate code type handling. TODO /** type handling in the intermediate code: * * cases: * 1) int/real: universal_integer | universal_real * 2) array of int/real: universal_*[card - 1] * 3) record: universal_*, array[card - 1], record * 4) array of record: record[card - 1] * * The intermediate code will only allow the definition of record * types and constraint array types. */ class GCTypes { public: //! calculate the upper bound of an array (if any) /** @param indices list of index constraints. * @return upper bound of the array (0-based), or 1 in case * no indexConstraint is present */ static universal_integer calcArrayBound(const std::list &indices); //! generate type elements of composite types. /** This class can be used, to generate type elements for composite * types. */ class GenTypeElements : public NullVisitor { public: //! c'tor /** @param addInitializer add an initial value. * @param uErrMsg error message, in case an unconstraint * array is found and no indexConstraint was * specified. * if uErrMsg is NULL, no error will be reported. * @param errNode node to report the error against (if any). * @param init optional constant initializer expression. */ GenTypeElements( bool addInitializer, const char *uErrMsg, const AstNode &errNode, const AstNode *constInitExp ); virtual void visit(RangeConstraintType &node); virtual void visit(EnumerationType &node); virtual void visit(SubtypeIndication &node); virtual void visit(RecordType &node); virtual void visit(UnconstrainedArrayType &node); virtual void visit(PhysicalType &node); void reset(void); /** contains all intermediate type elements of a composite * (i.e. record type). For arrays, must contain exactly one * TypeElement. */ std::list composite; /** return the list of indices applying down to the base type. * @return list with all index constraints */ std::list getIndices(void) const; /** list with all AST types that are referred to as final * elements of a record type. Should contain exactly one * element for an array type. */ std::list referredTypes; private: /** process a DiscreteRange * @param node DiscreteRange to process. * @param actualType actual referred to type. */ template void processDR( DiscreteRange &node, TypeDeclaration *actualType); template void processSI(SubtypeIndication &node); //! find the name of a referenced array or record type. /** @param node type declaration to find the name for * @return name of the referenced type. */ static std::string findName(const TypeDeclaration &node); void processSIArray(SubtypeIndication &node); //! calculate the upper bound of an array (if any) /** @return upper bound of the array (0-based), or 1 in case * no indexConstraint is present */ universal_integer calcArrayBound(void) const; //! calculate initial value elements. /** @return calculated initial value elements from * constInit member. */ std::list getInitValue(void) const; //! current set index constraints. std::list indexConstraint; //! initializer constraint DiscreteRange *constraint; //! add initializer to type elements? bool addInit; /** munge index constraints together? */ bool mungeIndices; /** error message, in case an unonstraint array w.o. * prior indexConstraint was found. */ const char *uAErrMsg; /** node to report the error against (if any). */ const AstNode &errorNode; /** is foreign inherited from a SubtypeIndication? */ bool isForeign; /** optional constant initializer expression */ const AstNode *constInit; }; class GenTypes : public NullVisitor { public: //! dummy c'tor to initialize members GenTypes() : type(NULL), indexConstraint(NULL) {} /** Visit an EnumerationType node. * @param node EnumerationType node that get's visited. */ virtual void visit(EnumerationType &node); /** Visit a RangeConstraintType node. * @param node RangeConstraintType node that get's visited. */ virtual void visit(RangeConstraintType &node); /** Visit a PhysicalType node. * @param node PhysicalType node that get's visited. */ virtual void visit(PhysicalType &node); /** Visit a RecordType node. * @param node RecordType node that get's visited. */ virtual void visit(RecordType &node); /** Visit an UnconstrainedArrayType node. * @param node UnconstrainedArrayType node that get's visited. */ virtual void visit(UnconstrainedArrayType &node); /** Visit a SubtypeIndication node. * @param node SubtypeIndication node that get's visited. */ virtual void visit(SubtypeIndication &node); /** collected type definition */ intermediate::Type *type; /** index constraint in case of subtype indications of arrays */ std::list *indexConstraint; }; }; }; /* namespace ast */ #endif /* __GC_TYPES_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/TransformSigAssign.hpp0000664000175000017500000000372411254460763022632 0ustar potyrapotyra/* $Id: TransformSigAssign.hpp 4676 2009-09-17 16:21:07Z potyra $ * * Transform concurrent signal assignment statements into equivalent * processes. * * Copyright (C) 2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TRANSFORM_SIGASSIGN_HPP_INCLUDED #define __TRANSFORM_SIGASSIGN_HPP_INCLUDED #include #include "frontend/visitor/TopDownVisitor.hpp" namespace ast { //! Transform concurrent signal assignments into processes /** This visitor will transform concurrent signal assignments into * the equivalent process-statements. */ class TransformSigAssign : public TopDownVisitor { public: //! c'tor TransformSigAssign() : sensitivities(std::list()), workList(NULL), deleteFlag(false), pickupSignals(false) {} private: /** Visit an Architecture node. * @param node Architecture node that get's visited. */ virtual void visit(Architecture &node); /** Visit a CondalSigAssign node. * @param node CondalSigAssign node that get's visited. */ virtual void visit(CondalSigAssign &node); /** Visit a SigAssignStat * @param node SigAssignStat node that gets visited. */ virtual void visit(SigAssignStat &node); /** Visit a WaveFormElem * @param node WaveFormElem node that gets visited. */ virtual void visit(WaveFormElem &node); /** Visit a SimpleName node. * @param node TemporaryName node that gets visited. */ virtual void visit(SimpleName &node); //! current list of sensitivities std::list sensitivities; //! current traversed list of concurrent statements. std::list *workList; //! delete currently traversed note? bool deleteFlag; //! pick up signals as sensitivities? bool pickupSignals; }; }; #endif /* __TRANSFORM_SIGASSIGN_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/ConstantPropagation.cpp0000664000175000017500000003363411263125767023044 0ustar potyrapotyra/* $Id: ConstantPropagation.cpp 4811 2009-10-07 14:55:51Z potyra $ * ConstantPropagation: propagate results of constant expressions. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/ConstantPropagation.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/ElementAssociation.hpp" #include "frontend/ast/ConditionedStat.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/TypeConversion.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/AssertStat.hpp" #include "frontend/ast/CaseStat.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/ConstArray.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/AttributeSpecification.hpp" #include "frontend/visitor/ResolveAggregates.hpp" #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include namespace ast { ConstantPropagation::ConstantPropagation() : constValue(NULL) { } void ConstantPropagation::visit(ConstInteger &node) { this->constValue = &node; } void ConstantPropagation::visit(ConstReal &node) { this->constValue = &node; } void ConstantPropagation::visit(FunctionCall &node) { assert(node.definition != NULL); FunctionDeclaration *decl = node.definition; bool isConst = true; std::list actuals; // FIXME this works only for positional arguments // FIXME this doesn't work for individual assoc for (std::list::iterator i = node.arguments->begin(); i != node.arguments->end(); i++) { assert((*i)->formal == NULL); this->reset(); (*i)->actual->accept(*this); isConst &= (this->constValue != NULL); this->setNode((*i)->actual); this->reset(); actuals.push_back((*i)->actual); } if ((decl->isBuiltin) && (isConst)) { this->optimizeBuiltin(node, actuals); return; } this->reset(); } void ConstantPropagation::visit(VarAssignStat &node) { assert(node.target != NULL); assert(node.source != NULL); node.target->accept(*this); this->reset(); node.source->accept(*this); this->setNode(node.source); this->reset(); } void ConstantPropagation::visit(SigAssignStat &node) { assert(node.target != NULL); assert(node.waveForm != NULL); node.target->accept(*this); this->reset(); this->listTraverse(*node.waveForm); } void ConstantPropagation::visit(WaveFormElem &node) { assert(node.value != NULL); node.value->accept(*this); this->setNode(node.value); this->reset(); if (node.delay == NULL) { return; } node.delay->accept(*this); this->setNode(node.delay); this->reset(); } void ConstantPropagation::visit(WhileLoopStat &node) { assert(node.condition != NULL); node.condition->accept(*this); bool r = this->setNode(node.condition); this->reset(); if (r) { ConstInteger *ci = dynamic_cast(node.condition); assert(ci != NULL); if (ci->value == 0) { // condition is false, loop will never execute. CompileError *ce = new CompileError( node, "While-loop will never be " "executed since condition is never " "met."); ErrorRegistry::addWarning(ce); util::MiscUtil::lterminate(node.loopStats); node.loopStats = new std::list(); } } assert(node.loopStats != NULL); this->listTraverse(*node.loopStats); } void ConstantPropagation::visit(Subscript &node) { assert(node.source != NULL); assert(node.indices != NULL); // TODO can even optimize the subscription itself, if // indices + source are constant node.source->accept(*this); bool r = this->setNode(node.source); this->reset(); r &= this->listOptimize(node.indices); if (! r) { return; } ConstArray *ca = dynamic_cast(node.source); if (ca == NULL) { return; } // if it's a ConstArray, then (currently) there's exactly one // index. assert(node.indices != NULL); assert(node.indices->size() == 1); const Expression *idxE = node.indices->front(); const ConstInteger *ci = dynamic_cast(idxE); assert(ci != NULL); // FIXME bounds/direction can diverge from [0 to len]! assert(ca->elements != NULL); assert(0 <= ci->value); const size_t idx = static_cast(ci->value); assert(idx < ca->elements->size()); ConstInteger *result = (*ca->elements)[idx]; this->constValue = result; } void ConstantPropagation::visit(Slice &node) { assert(node.source != NULL); node.source->accept(*this); bool sc = this->setNode(node.source); /* FIXME throw an error instead of assert() */ assert(! sc); /* constant source cannot get sliced */ this->reset(); node.range->accept(*this); this->reset(); /* FIXME not needed, once DiscreteRange is there */ } void ConstantPropagation::visit(TypeConversion &node) { assert(node.source != NULL); node.source->accept(*this); // TODO this actually adds a hard barrier at a TypeConversion node. // see sample implementation below how it should get circumvented. // The sample implementation however doesn't solve int<->real // conversions. this->setNode(node.source); this->reset(); #if 0 /* FIXME must think over this again */ if (this->constValue != NULL) { assert(node.baseType == this->constValue.baseType); this->constValue.type = new SubtypeIndication(node.targetType, node.location); } #endif } void ConstantPropagation::visit(SimpleName &node) { this->reset(); // find out if it is a constant. if (node.candidates.size() != 1) { return; } Symbol *sym = node.candidates.front(); switch(sym->type) { case SYMBOL_VARIABLE: break; default: /* cannot be a constant */ return; } ConstantDeclaration *cd = dynamic_cast(&sym->declaration); if (cd == NULL) { /* not a constant */ return; } if (! cd->fixedValue) { return; } assert(cd->init != NULL); // parser should have taken care for this. this->constValue = cd->init; } void ConstantPropagation::visit(SelectedName &node) { node.prefix->accept(*this); bool pc = this->setNode(node.prefix); /* FIXME report error */ assert(! pc); // const prefix doesn't make sense this->reset(); } void ConstantPropagation::visit(AttributeName &node) { node.prefix->accept(*this); bool pc = this->setNode(node.prefix); /* FIXME report error */ assert(! pc); // const prefix doesn't make sense this->reset(); } void ConstantPropagation::visit(TemporaryName &node) { assert(node.prefix != NULL); node.prefix->accept(*this); this->setNode(node.prefix); this->reset(); } void ConstantPropagation::visit(WaitStat &node) { this->process(node); if (node.timeout != NULL) { node.timeout->accept(*this); this->setNode(node.timeout); this->reset(); } if (node.sensitivities == NULL) { return; } for (std::list::iterator i = node.sensitivities->begin(); i != node.sensitivities->end(); i++) { (*i)->accept(*this); // don't set any node here this->reset(); } } void ConstantPropagation::visit(ReturnStat &node) { if (node.result != NULL) { node.result->accept(*this); this->setNode(node.result); this->reset(); } } void ConstantPropagation::visit(AssertStat &node) { this->process(node); if (node.report != NULL) { node.report->accept(*this); this->setNode(node.report); this->reset(); } if (node.severity != NULL) { node.severity->accept(*this); this->setNode(node.severity); this->reset(); } } void ConstantPropagation::visit(DiscreteRange &node) { if (node.from != NULL) { node.from->accept(*this); this->setNode(node.from); this->reset(); assert(node.to != NULL); node.to->accept(*this); this->setNode(node.to); this->reset(); return; } if (node.rangeName != NULL) { node.rangeName->accept(*this); this->reset(); return; } } void ConstantPropagation::visit(CaseStat &node) { assert(node.select != NULL); node.select->accept(*this); this->setNode(node.select); this->reset(); assert(node.alternatives != NULL); this->listTraverse(*node.alternatives); } void ConstantPropagation::visit(CaseAlternative &node) { assert(node.isVals != NULL); this->listOptimize(node.isVals); if (node.thenStats != NULL) { this->listTraverse(*node.thenStats); } } void ConstantPropagation::visit(Aggregate &node) { bool isConstArray = true; assert(node.associations != NULL); for (std::list::iterator i = node.associations->begin(); i != node.associations->end(); i++) { this->listOptimize((*i)->choices); assert((*i)->actual != NULL); (*i)->actual->accept(*this); bool r = this->setNode((*i)->actual); this->reset(); isConstArray &= r; } if (! isConstArray) { return; } // array is const, check ranges first. std::list idcs = std::list(); const UnconstrainedArrayType *bt = ResolveTypes::pickupIndexConstraint(node.type, idcs); DiscreteRange *neededIndex; if (idcs.size() == 0) { neededIndex = ResolveTypes::determineIndexRangeAgg( bt, *node.associations); assert(neededIndex != NULL); } else { neededIndex = idcs.front(); } ResolveAggregates ra = ResolveAggregates(*neededIndex); node.accept(ra); std::vector elems = std::vector(); enum DiscreteRange::Direction d = neededIndex->direction; for (universal_integer i = neededIndex->getLeftBound(); (i * d) <= (neededIndex->getRightBound() * d); i += d) { ElementAssociation *assoc = this->findAggregateAssoc(i, node); if (assoc == NULL) { /* error -> return early. */ return; } ConstInteger *ci = dynamic_cast(assoc->actual); if (ci == NULL) { return; } elems.push_back(ci); } ConstArray *ca = new ConstArray( new std::vector(elems), node.location); ca->type = ConstantPropagation::makeCAType(node.type, elems.size()); this->constValue = ca; } void ConstantPropagation::visit(AttributeSpecification &node) { assert(node.init != NULL); node.init->accept(*this); bool r = this->setNode(node.init); if (! r) { // FIXME this is only true for *some* occurances, // cf. LRM 5.1 CompileError *ce = new CompileError(*node.init, "Non static initilizers for " "attribte specifications are " "currently not supported."); ErrorRegistry::addError(ce); } this->reset(); } void ConstantPropagation::optimizeBuiltin( FunctionCall &node, std::list args ) { assert(node.definition != NULL); if (! node.definition->isBuiltin) { return; } if (node.definition->builtin == NULL) { std::cerr << "WARNING: no builtin defined for " << node.definition->location << ": " << node.definition << std::endl; return; } BuiltinFunction *bf = node.definition->builtin; this->constValue = bf->execute(args); } bool ConstantPropagation::setNode(Expression *&node) const { if (this->constValue == NULL) { return false; } if (this->constValue == node) { return true; } node = this->constValue; return true; } void ConstantPropagation::visit(AssociationElement &node) { this->reset(); assert(node.actual != NULL); node.actual->accept(*this); this->setNode(node.actual); this->reset(); } void ConstantPropagation::process(AstNode &node) { this->reset(); } void ConstantPropagation::process(ValDeclaration &node) { if (node.init != NULL) { node.init->accept(*this); if (this->setNode(node.init)) { // TODO propagate } this->reset(); } /* do some out of order traversal */ assert(node.subtypeIndic != NULL); node.subtypeIndic->accept(*this); } void ConstantPropagation::process(ConditionedStat &node) { if (node.condition != NULL) { node.condition->accept(*this); this->setNode(node.condition); this->reset(); //FIXME should have some effect on the condition. } } void ConstantPropagation::reset(void) { this->constValue = NULL; } bool ConstantPropagation::listOptimize(std::list *l) { bool ret = true; if (l == NULL) { return false; } for (std::list::iterator i = l->begin(); i != l->end(); i++) { (*i)->accept(*this); ret &= this->setNode(*i); this->reset(); } return ret; } ElementAssociation * ConstantPropagation::findAggregateAssoc( universal_integer index, Aggregate &node ) const { for (std::list::iterator i = node.associations->begin(); i != node.associations->end(); i++) { if ((*i)->range == NULL) { return NULL; } if ((*i)->range->contains(index)) { return *i; } } return NULL; } TypeDeclaration * ConstantPropagation::makeCAType(TypeDeclaration *haveType, size_t numElems) { std::list idxC = std::list(); const UnconstrainedArrayType *ua = ResolveTypes::pickupIndexConstraint(haveType, idxC); // perform subtype conversion, if there is a constraint target // type present. if (idxC.size() > 0) { // subtype conversion takes place, use inferred subtype. return haveType; } TypeDeclaration *bt = const_cast(ua); ConstInteger *lb = new ConstInteger(0, haveType->location); ConstInteger *ub = new ConstInteger(static_cast(numElems) - 1, haveType->location); DiscreteRange *dr = new DiscreteRange(lb, ub, DiscreteRange::DIRECTION_UP, haveType->location); SubtypeIndication *si = new SubtypeIndication(bt, haveType->location); si->indexConstraint = new std::list(); si->indexConstraint->push_back(dr); return si; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/DotVisitor.cpp0000664000175000017500000006445611502700163021144 0ustar potyrapotyra/* $Id: DotVisitor.cpp 5082 2010-12-17 15:23:31Z potyra $ * DotVisitor: create a .dot graph representation of the abstract syntax * tree. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include "frontend/visitor/DotVisitor.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/IfStat.hpp" #include "frontend/ast/NullStat.hpp" #include "frontend/ast/ForLoopStat.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/NextStat.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/ExitStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/WaveFormElem.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/AssertStat.hpp" #include "frontend/ast/VarDeclaration.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/CaseStat.hpp" #include "frontend/ast/CaseAlternative.hpp" #include "frontend/ast/Others.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/PackageBody.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/SubprogBody.hpp" #include "frontend/ast/CondalSigAssign.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/ElementAssociation.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/ast/Library.hpp" #include "frontend/ast/LibraryList.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/TypeConversion.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/ConstArray.hpp" #include "frontend/ast/AttributeDeclaration.hpp" #include "frontend/ast/AttributeSpecification.hpp" #include "util/MiscUtil.hpp" namespace ast { DotVisitor::DotVisitor() : idCounter(0), currentDesc(NULL) { } DotVisitor::~DotVisitor() { //free descritptions for (std::list::iterator i = this->nodes.begin(); i != this->nodes.end(); i++) { delete *i; } } void DotVisitor::visit(ElementAssociation& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "Association"); if (node.choices != NULL) { this->listTraverse(*node.choices); this->makeEdges(d->id, *node.choices, "choice"); } if (node.actual != NULL) { node.actual->accept(*this); this->edges.push_back( Edge(d->id, node.actual->number, "actual")); } this->process(node); } void DotVisitor::visit(ConstInteger& node) { //FIXME DotVisitor::NodeDescription *d = this->makeDescription(node, "ConstInteger"); d->add(util::MiscUtil::toString(node.value)); this->process(node); } void DotVisitor::visit(ConstReal& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "ConstReal"); d->add(util::MiscUtil::toString(node.value)); this->process(node); } void DotVisitor::visit(ConstArray &node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "ConstArray"); this->process(node); this->listTraverse(*node.elements); this->makeEdges(d->id, *node.elements); } void DotVisitor::visit(SimpleName& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "SimpleName"); assert(node.name != NULL); d->add(*node.name); std::string expandedPrefix = ""; for (std::list::const_iterator i = node.prefixStrings.begin(); i != node.prefixStrings.end(); i++) { if (i != node.prefixStrings.begin()) { expandedPrefix += "."; } expandedPrefix += **i; } if (! expandedPrefix.empty()) { d->add("Scope", expandedPrefix); } } void DotVisitor::visit(SelectedName& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "SelectedName"); assert(node.name != NULL); d->add(*node.name); this->process(node); } void DotVisitor::visit(AttributeName& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "AttributeName"); assert(node.name != NULL); d->add(*node.name); this->process(node); } void DotVisitor::visit(TemporaryName& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "TemporaryName"); d->add("(unnamed)"); this->process(node); } void DotVisitor::visit(Entity& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "Entity"); this->process(node); /* traverse ports */ if (node.ports != NULL) { this->listTraverse(*node.ports); this->makeEdges(d->id, *node.ports, "ports"); } /* traverse generics */ if (node.generics != NULL) { this->listTraverse(*node.generics); this->makeEdges(d->id, *node.generics, "generics"); } } void DotVisitor::visit(LibraryList& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "Libraries"); this->process(node); this->listTraverse(node.libraries); this->makeEdges(d->id, node.libraries); } void DotVisitor::visit(SignalDeclaration& node) { this->makeDescription(node, "SignalDeclaration"); this->process(node); } void DotVisitor::visit(ConstantDeclaration& node) { this->makeDescription(node, "ConstantDeclaration"); this->process(node); } void DotVisitor::visit(FunctionCall& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "FunctionCall"); this->process(node); if (node.subprog) { node.subprog->accept(*this); this->edges.push_back(Edge(d->id, node.subprog->number, "name")); } if (node.arguments) { this->listTraverse(*node.arguments); this->makeEdges(d->id, *node.arguments, "arg"); } } void DotVisitor::visit(IfStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "IF"); this->process(node); if (node.thenStats) { this->listTraverse(*node.thenStats); this->makeEdges(d->id, *node.thenStats, "then"); } if (node.elseStats) { this->listTraverse(*node.elseStats); this->makeEdges(d->id, *node.elseStats, "else"); } } void DotVisitor::visit(NullStat& node) { this->makeDescription(node, "NULL"); this->process(node); } void DotVisitor::visit(ForLoopStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "FOR"); this->process(node); if (node.loopVariable != NULL) { node.loopVariable->accept(*this); this->edges.push_back( Edge(d->id, node.loopVariable->number, "counter")); } /* traverse to discrete range */ if (node.range != NULL) { node.range->accept(*this); this->edges.push_back( Edge(d->id, node.range->number, "range")); } } void DotVisitor::visit(WhileLoopStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "WHILE"); this->process(node); /* traverse condition */ if (node.condition) { node.condition->accept(*this); this->edges.push_back( Edge(d->id, node.condition->number, "cond")); } } void DotVisitor::visit(NextStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "NEXT"); if (node.loopLabel) { d->add("label", *(node.loopLabel->name)); } this->process(node); } void DotVisitor::visit(VarAssignStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, ":="); this->process(node); /* traverse to target */ if (node.target) { node.target->accept(*this); this->edges.push_back(Edge(d->id, node.target->number)); } /* traverse to source */ if (node.source) { node.source->accept(*this); this->edges.push_back(Edge(d->id, node.source->number)); } } void DotVisitor::visit(WaitStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "WAIT"); this->process(node); /* traverse to Sensitivity list */ if (node.sensitivities) { this->listTraverse(*node.sensitivities); this->makeEdges(d->id, *node.sensitivities, "on"); } /* traverse to timeout */ if (node.timeout) { node.timeout->accept(*this); this->edges.push_back( Edge(d->id, node.timeout->number, "until")); } } void DotVisitor::visit(ExitStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "EXIT"); if (node.loopLabel) { d->add("Label:", *(node.loopLabel->name)); } this->process(node); } void DotVisitor::visit(SigAssignStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "<="); this->process(node); /* traverse to target */ if (node.target != NULL) { node.target->accept(*this); this->edges.push_back( Edge(d->id, node.target->number, "target")); } /* traverse to waveForm */ if (node.waveForm != NULL) { this->listTraverse(*node.waveForm); this->makeEdges(d->id, *node.waveForm); } } void DotVisitor::visit(WaveFormElem& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "WaveFormElement"); this->process(node); /* traverse to value */ if (node.value != NULL) { node.value->accept(*this); this->edges.push_back(Edge(d->id, node.value->number)); } /* traverse to delay */ if (node.delay != NULL) { node.delay->accept(*this); this->edges.push_back( Edge(d->id, node.delay->number, "after")); } } void DotVisitor::visit(ReturnStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "RETURN"); this->process(node); /* traverse to result */ if (node.result != NULL) { node.result->accept(*this); this->edges.push_back(Edge(d->id, node.result->number)); } } void DotVisitor::visit(ProcCallStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "ProcCall"); this->process(node); /* traverse to referring symbol */ if (node.subprog != NULL) { node.subprog->accept(*this); this->edges.push_back(Edge(d->id, node.subprog->number, "name")); } /* traverse to arguments */ if (node.arguments != NULL) { this->listTraverse(*node.arguments); this->makeEdges(d->id, *node.arguments); } } void DotVisitor::visit(AssertStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "ASSERT"); this->process(node); /* traverse to report expression */ if (node.report != NULL) { node.report->accept(*this); this->edges.push_back( Edge(d->id, node.report->number, "REPORT")); } /* traverse to severity expression */ if (node.severity != NULL) { node.severity->accept(*this); this->edges.push_back( Edge(d->id, node.severity->number, "SEVERITY")); } } void DotVisitor::visit(VarDeclaration& node) { this->makeDescription(node, "VarDecl"); this->process(node); } void DotVisitor::visit(DiscreteRange& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "DiscreteRange"); switch(node.direction) { case DiscreteRange::DIRECTION_UP: d->add("TO"); break; case DiscreteRange::DIRECTION_DOWN: d->add("DOWNTO"); break; } this->process(node); /* traverse to from */ if (node.from != NULL) { node.from->accept(*this); this->edges.push_back(Edge(d->id, node.from->number, "from")); } /* traverse to */ if (node.to != NULL) { node.to->accept(*this); this->edges.push_back(Edge(d->id, node.to->number, "(down)to")); } if (node.rangeName != NULL) { node.rangeName->accept(*this); this->edges.push_back( Edge(d->id, node.rangeName->number, "RangebyName")); } } void DotVisitor::visit(CaseStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "CASE"); this->process(node); /* traverse to select */ if (node.select != NULL) { node.select->accept(*this); this->edges.push_back( Edge(d->id, node.select->number, "selector")); } /* traverse to alternatives */ if (node.alternatives != NULL) { this->listTraverse(*node.alternatives); this->makeEdges(d->id, *node.alternatives); } } void DotVisitor::visit(CaseAlternative& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "CaseAlternative"); this->process(node); /* traverse to isVals */ if (node.isVals != NULL) { this->listTraverse(*node.isVals); this->makeEdges(d->id, *node.isVals, "is"); } /* traverse to thenStats */ if (node.thenStats != NULL) { this->listTraverse(*node.thenStats); this->makeEdges(d->id, *node.thenStats); } } void DotVisitor::visit(Others& node) { this->makeDescription(node, "OTHERS"); this->process(node); } void DotVisitor::visit(Architecture& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "Architecture"); this->process(node); /* traverse to concurrentStats */ if (node.concurrentStats != NULL) { this->listTraverse(*node.concurrentStats); this->makeEdges(d->id, *node.concurrentStats); } } void DotVisitor::visit(AssociationElement& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "AssociationElement"); this->process(node); /* traverse to formalPart */ if (node.formal != NULL) { node.formal->accept(*this); this->edges.push_back( Edge(d->id, node.formal->number, "formal")); } /* traverse to actualPart */ if (node.actual != NULL) { node.actual->accept(*this); this->edges.push_back( Edge(d->id, node.actual->number, "actual")); } } void DotVisitor::visit(FunctionDeclaration& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "FUNCTION"); this->process(node); if (node.returnType != NULL) { node.returnType->accept(*this); this->edges.push_back( Edge(d->id, node.returnType->number, "returnT")); } if (node.isPure) { d->add("pure"); } } void DotVisitor::visit(ProcedureDeclaration& node) { this->makeDescription(node, "PROCEDURE"); this->process(node); } void DotVisitor::visit(CompInstStat& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "CompInstStat"); this->process(node); /* traverse to entityName */ if (node.entityName != NULL) { node.entityName->accept(*this); this->edges.push_back(Edge(d->id, node.entityName->number)); } /* traverse to genericMap */ if (node.genericMap != NULL) { this->listTraverse(*node.genericMap); this->makeEdges(d->id, *node.genericMap, "GENERIC MAP"); } /* traverse to portMap */ if (node.portMap != NULL) { this->listTraverse(*node.portMap); this->makeEdges(d->id, *node.portMap, "PORT MAP"); } } void DotVisitor::visit(Package& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "PACKAGE"); this->process(node); /* traverse to entityName */ if (node.body != NULL) { node.body->accept(*this); this->edges.push_back(Edge(d->id, node.body->number)); } } void DotVisitor::visit(PackageBody& node) { this->makeDescription(node, "PACKAGE BODY"); this->process(node); } void DotVisitor::visit(Process& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "PROCESS"); this->process(node); if (node.sensitivityList != NULL) { this->listTraverse(*node.sensitivityList); this->makeEdges(d->id, *node.sensitivityList, "sensitivities"); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); this->makeEdges(d->id, *node.declarations, "decls"); } if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); this->makeEdges(d->id, *node.seqStats); } } void DotVisitor::visit(SubprogBody& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "SubprogBody"); this->process(node); if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); this->makeEdges(d->id, *node.seqStats); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); this->makeEdges(d->id, *node.declarations); } } void DotVisitor::visit(CondalSigAssign& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "<= (condal)"); this->process(node); if (node.target != NULL) { node.target->accept(*this); this->edges.push_back( Edge(d->id, node.target->number, "target")); } if (node.assignStat != NULL) { node.assignStat->accept(*this); this->edges.push_back(Edge(d->id, node.assignStat->number)); } } void DotVisitor::visit(EnumerationType& node) { this->makeDescription(node, "EnumerationType"); this->process(node); } void DotVisitor::visit(PhysicalType& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "PhysicalType"); this->process(node); if (node.constraint != NULL) { node.constraint->accept(*this); this->edges.push_back(Edge(d->id, node.constraint->number)); } if (node.units != NULL) { this->listTraverse(*node.units); this->makeEdges(d->id, *node.units); } } void DotVisitor::visit(PhysicalTypeUnit& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "PhysicalTypeUnit"); this->process(node); if (node.physUnit != NULL) { node.physUnit->accept(*this); this->edges.push_back(Edge(d->id, node.physUnit->number)); } } void DotVisitor::visit(RangeConstraintType& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "RANGE"); this->process(node); if (node.constraint != NULL) { node.constraint->accept(*this); this->edges.push_back(Edge(d->id, node.constraint->number)); } } void DotVisitor::visit(UnconstrainedArrayType& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "ARRAY<>"); this->process(node); if (node.indexTypes != NULL) { this->listTraverse(*node.indexTypes); this->makeEdges(d->id, *node.indexTypes); } //FIXME new members } void DotVisitor::visit(RecordType& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "RECORD"); this->process(node); if (node.elements != NULL) { this->listTraverse(*(node.elements)); this->makeEdges(d->id, *node.elements); } } void DotVisitor::visit(RecordTypeElement& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "RecordElement"); this->process(node); if (node.subtype) { node.subtype->accept(*this); this->edges.push_back(Edge(d->id, node.subtype->number)); } } void DotVisitor::visit(Aggregate& node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "Aggregate"); this->process(node); if (node.associations) { this->listTraverse(*node.associations); this->makeEdges(d->id, *node.associations); } } void DotVisitor::visit(SubtypeIndication &node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "SubtypeIndication"); this->process(node); if (node.typeName != NULL) { node.typeName->accept(*this); this->edges.push_back(Edge(d->id, node.typeName->number)); } if (node.constraint != NULL) { node.constraint->accept(*this); this->edges.push_back(Edge(d->id, node.constraint->number)); } if (node.indexConstraint != NULL) { this->listTraverse(*node.indexConstraint); this->makeEdges(d->id, *node.indexConstraint); } if (node.resolutionFunction != NULL) { node.resolutionFunction->accept(*this); this->edges.push_back( Edge(d->id, node.resolutionFunction->number)); } } void DotVisitor::visit(Library &node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "LibUnits"); this->process(node); this->listTraverse(node.units); this->makeEdges(d->id, node.units); } void DotVisitor::visit(Subscript &node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "Subscript"); if (node.source != NULL) { node.source->accept(*this); this->edges.push_back(Edge(d->id, node.source->number)); } if (node.indices != NULL) { this->listTraverse(*node.indices); this->makeEdges(d->id, *node.indices, "index"); } } void DotVisitor::visit(Slice &node) { DotVisitor::NodeDescription *d = this->makeDescription(node, "Slice"); if (node.source != NULL) { node.source->accept(*this); this->edges.push_back(Edge(d->id, node.source->number)); } if (node.range != NULL) { node.range->accept(*this); this->edges.push_back( Edge(d->id, node.range->number, "range")); } } void DotVisitor::visit(TypeConversion &node) { DotVisitor::NodeDescription* d = this->makeDescription(node, "TypeConversion"); this->process(node); if (node.source != NULL) { node.source->accept(*this); this->edges.push_back(Edge(d->id, node.source->number)); } //TODO target type name would be of interest. } void DotVisitor::visit(AttributeDeclaration &node) { this->makeDescription(node, "ATTRIBUTE"); this->process(node); } void DotVisitor::visit(AttributeSpecification &node) { DotVisitor::NodeDescription* d = this->makeDescription(node, "AttributeSpec"); this->process(node); assert(node.init != NULL); node.init->accept(*this); this->edges.push_back(Edge(d->id, node.init->number)); /* FIXME edge to declaration? */ } void DotVisitor::process(ValDeclaration& node) { DotVisitor::NodeDescription *d = this->currentDesc; switch (node.mode) { case ValDeclaration::MODE_IN: d->add("Mode", "in"); break; case ValDeclaration::MODE_OUT: d->add("Mode", "out"); break; case ValDeclaration::MODE_INOUT: d->add("Mode", "inout"); break; } SymbolDeclaration& sNode = static_cast(node); this->process(sNode); /* traverse to initializer */ if (node.init != NULL) { node.init->accept(*this); this->edges.push_back( Edge(d->id, node.init->number, "initializer")); } /* traverse to subtype indic */ if (node.subtypeIndic != NULL) { node.subtypeIndic->accept(*this); this->edges.push_back( Edge(d->id, node.subtypeIndic->number, "subtype")); } } void DotVisitor::process(SymbolDeclaration& node) { DotVisitor::NodeDescription *d = this->currentDesc; if (node.name) { d->add("Name", *node.name); } AstNode& aNode = static_cast(node); this->process(aNode); } void DotVisitor::process(Expression& node) { AstNode& aNode = static_cast(node); this->process(aNode); } void DotVisitor::process(SeqStat& node) { AstNode& anode = static_cast(node); this->process(anode); } void DotVisitor::process(LoopStat& node) { DotVisitor::NodeDescription *d = this->currentDesc; if (node.name) { d->add("Label", *node.name); } SeqStat& snode = static_cast(node); this->process(snode); /* taverse to loopStats */ if (node.loopStats != NULL) { this->listTraverse(*node.loopStats); this->makeEdges(d->id, *node.loopStats); } } void DotVisitor::process(ConditionedStat& node) { DotVisitor::NodeDescription *d = this->currentDesc; SeqStat& snode = static_cast(node); this->process(snode); /* taverse to condition */ if (node.condition != NULL) { node.condition->accept(*this); this->edges.push_back( Edge(d->id, node.condition->number, "cond")); } } void DotVisitor::process(Callable& node) { DotVisitor::NodeDescription *d = this->currentDesc; SymbolDeclaration& snode = static_cast(node); this->process(snode); /* taverse to arguments */ if (node.arguments != NULL) { this->listTraverse(*node.arguments); this->makeEdges(d->id, *node.arguments); } if (node.definition != NULL) { node.definition->accept(*this); this->edges.push_back( Edge(d->id, node.definition->number, "body")); } } void DotVisitor::process(LibUnit& node) { DotVisitor::NodeDescription *d = this->currentDesc; SymbolDeclaration& snode = static_cast(node); this->process(snode); if (node.libClauses) { this->listTraverse(*node.libClauses); this->makeEdges(d->id, *node.libClauses, "lib"); } /* taverse to useClauses */ if (node.useClauses != NULL) { this->listTraverse(*node.useClauses); this->makeEdges(d->id, *node.useClauses, "use"); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); this->makeEdges(d->id, *node.declarations, "decl"); } } void DotVisitor::process(TypeDeclaration& node) { SymbolDeclaration& snode = static_cast(node); this->process(snode); } void DotVisitor::process(Name &node) { //do nothing. } void DotVisitor::process(PrefixedName &node) { DotVisitor::NodeDescription *d = this->currentDesc; if (node.prefix != NULL) { node.prefix->accept(*this); this->edges.push_back(Edge(d->id, node.prefix->number, "prefix")); } } /* *************** END visiotor Methods ******************* */ DotVisitor::NodeDescription* DotVisitor::makeDescription(AstNode& node, const char* desc) { int id = this->assignId(node); DotVisitor::NodeDescription *d = new DotVisitor::NodeDescription(id, desc); this->nodes.push_back(d); this->currentDesc = d; return d; } int DotVisitor::assignId(AstNode& node) { this->idCounter++; node.number = this->idCounter; return this->idCounter; } void DotVisitor::put(std::ostream& stream) const { stream << "digraph AST {" << std::endl; for (std::list::const_iterator i = this->nodes.begin(); i != this->nodes.end(); i++) { (*i)->put(stream); } // put all edges for (std::list::const_iterator i = this->edges.begin(); i != this->edges.end(); i++) { i->put(stream); } stream << "}" << std::endl; } /* ***************** nested class Edge ******************** */ DotVisitor::Edge::~Edge() { delete this->label; } void DotVisitor::Edge::put(std::ostream& stream) const { stream << this->from << " -> " << this->to; if (this->label) { stream << "[label=\"" << *(this->label) << "\"]"; } stream << ";" << std::endl; } /* ************* nested class NodeDescription ********** */ void DotVisitor::NodeDescription::add(std::string n, std::string value) { this->attributes.push_back("\\n" + n + ": " + value); } void DotVisitor::NodeDescription::add(std::string n) { this->attributes.push_back("\\n" + n); } void DotVisitor::NodeDescription::put(std::ostream& stream) const { stream << this->id << " [label=\"" << this->name; for (std::list::const_iterator i = this->attributes.begin(); i != this->attributes.end(); i++) { stream << *i; } stream << "\", shape=\"rect\"];" << std::endl; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/CheckAccessMode.hpp0000664000175000017500000000671311137610234022002 0ustar potyrapotyra/* $Id: CheckAccessMode.hpp 4323 2009-01-27 13:48:12Z potyra $ * CheckAccessMode: visitor to check if reading/writing data is permitted * via in,inout,out access modes. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CHECK_ACCESS_MODES_HPP_INCLUDED #define __CHECK_ACCESS_MODES_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" #include "frontend/ast/ValDeclaration.hpp" namespace ast { //! check if reading/writing to a data/signal/constant is permitted. /** Dependencies: * - ResolveTypes * - NormalizeAssocs */ class CheckAccessMode : public TopDownVisitor { public: //! c'tor CheckAccessMode() : accessMode(ValDeclaration::MODE_IN), isForeign(false) {} private: /** visit a SimpleName * @param node node that get's visited. */ virtual void visit(SimpleName &node); /** Visit a VarAssignStat * @param node VarAssignStat node that get's visited. */ virtual void visit(VarAssignStat &node); /** Visit a SigAssignStat * @param node SigAssignStat node that get's visited. */ virtual void visit(SigAssignStat &node); /** Visit a CompInstStat node. * @param node CompInstStat node that get's visited. */ virtual void visit(CompInstStat& node); /** Visit a Subscript node. * @param node Subscript node that get's visited. */ virtual void visit(Subscript &node); /** Visit a Slice node. * @param node Slice node that get's visited. */ virtual void visit(Slice &node); /** Visit an Aggregate node. * @param node Aggregate node that get's visited. */ virtual void visit(Aggregate &node); /** visit a ConstInteger * @param node node that get's visited. */ virtual void visit(ConstInteger &node); /** visit a ConstReal * @param node node that get's visited. */ virtual void visit(ConstReal &node); /** visit a ConstArray * @param node node that get's visited. */ virtual void visit(ConstArray &node); /** Visit a FunctionCall. * @param node FunctionCall node that get's visited. */ virtual void visit(FunctionCall &node); /** Visit a ProcCallStat * @param node ReturnStat node that get's visited. */ virtual void visit(ProcCallStat &node); /** Visit an Entity declaration. * @param node Entity Declaration node that get's visited. */ virtual void visit(Entity &node); /** process a function call or procedure call. * @param args argument list * @param node corresponding Callable definition. */ void processCall( std::list &args, const Callable &node ); //! Process a generic Callable. /** This function will get called for each Callable (or class * derived from Callable) that get's visited. * * @param node Callable instance. */ virtual void process(Callable &node); /** process a constant leaf node. * Will report an error, if the node is to be accessed * via INOUT or OUT. * @param node leaf node. */ void processConst(const Expression &node) const; //! how is the current variable accessed? ValDeclaration::Mode accessMode; //! actual designator of a foreign CompInstStat/subprogram call? bool isForeign; }; }; /* namespace ast */ #endif /* __CHECK_ACCESS_MODES_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/DotVisitor.tpp0000664000175000017500000000177011137620345021162 0ustar potyrapotyra/* $Id: DotVisitor.tpp 4331 2009-01-27 14:57:41Z potyra $ * vim:tabstop=8:shiftwidth=8:filetype=cpp:textwidth=72: * DotVisitor: create a .dot graph representation of the abstract syntax * tree. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ namespace ast { template void DotVisitor::makeEdges(int fromId, T l) { for (typename T::const_iterator i = l.begin(); i != l.end(); i++) { if (*i) { this->edges.push_back( DotVisitor::Edge(fromId, (*i)->number)); } } } template void DotVisitor::makeEdges(int fromId, T l, const char* s) { for (typename T::const_iterator i = l.begin(); i != l.end(); i++) { if (*i) { this->edges.push_back( DotVisitor::Edge( fromId, (*i)->number, s)); } } } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/UnconstraintBounds.hpp0000664000175000017500000000577411163205232022703 0ustar potyrapotyra/* $Id: UnconstraintBounds.hpp 4430 2009-03-27 17:19:22Z potyra $ * * Resolve ranges of positional and named aggregates, where the type * is an unconstraint array. * * Copyright (C) 2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __UNCONSTRAINT_BOUNDS_HPP_INCLUDED #define __UNCONSTRAINT_BOUNDS_HPP_INCLUDED #include "frontend/visitor/NullVisitor.hpp" #include "frontend/ast/Types.hpp" namespace ast { //! Resolve the bounds of an unconstraint array aggregate. /** This visitor can be used to determine the bounds of an unconstraint * Array Aggregate. * * It is useful wherever a an unconstraint variable/parameter/port * will get its actual constraints from the initializer. * * In contrast to ResolveAggregates, this visitor will not set element * position number, but only determine the bounds and direction. * * This visitor should be used only on small portions of the syntax * tree, i.e. only Aggregates should accept it. * * Important: This visitor assumes that the type of the Aggregate has been * determined already, but that it is an unconstraint type. * It is definitely wrong to use this visitor for a constraint * type. */ class UnconstraintBounds : public NullVisitor { public: //! dummy c'tor UnconstraintBounds(); //! dummy d'tor virtual ~UnconstraintBounds() {} //! picked up bounds (if any) DiscreteRange *bounds; private: /** Visit an Aggregate node. * @param node Aggregate node that get's visited. */ virtual void visit(Aggregate &node); /** visit a ElementAssociation * @param node node that get's visited. */ virtual void visit(ElementAssociation &node); /** Visit an Others node. * @param node Others node that get's visited. */ virtual void visit(Others &node); /** Visit a ConstInteger node. * @param node ConstInteger node that get's visited. */ virtual void visit(ConstInteger &node); /** Visit a DiscreteRange * @param node DiscreteRange node that get's visited. */ virtual void visit(DiscreteRange &node); //! Process a generic AstNode. /** Failmatch method. Must not be called. * * @param node AstNode */ virtual void process(AstNode &node); /** determine the index range of the unconstraint array at by * the index type. * @param at unconstraint array type. * @return index range of the index subtype of at */ static DiscreteRange * findIndexRange(const UnconstrainedArrayType *at); /** low bound of determined index */ universal_integer low; /** high bound of determined index */ universal_integer high; /** number of elements for positional aggregates */ size_t numElements; /** is it a positional aggregate? */ bool positional; }; }; /* namespace ast */ #endif /* __UNCONSTRAINT_BOUNDS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GCRegisterSet.cpp0000664000175000017500000001000711244534774021507 0ustar potyrapotyra/* $Id: GCRegisterSet.cpp 4585 2009-08-24 16:04:12Z potyra $ * * RegisterSet defines a means to address signals, drivers, values, and to * apply operations on these. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/GCRegisterSet.hpp" #include #include "intermediate/opcodes/GetSig.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/operands/IndirectOperand.hpp" #include "intermediate/operands/RegisterFactory.hpp" #include "frontend/visitor/GCArrays.hpp" namespace ast { using namespace intermediate; Operand * RegisterSet::getValue(enum BaseType bt) { enum OpType ot = toOpType(bt); if (this->isSignal) { if (this->value != NULL) { return this->value; } // generated code to access the signal first, and cache the // result in value assert(this->composite != NULL); Register *compositeReg = dynamic_cast(this->composite); if (compositeReg == NULL) { compositeReg = this->cc->createRegister(OP_TYPE_POINTER); Mov *toReg = new Mov(this->composite, compositeReg); this->cc->addCode(toReg); } IndirectOperand *pToSig = new IndirectOperand(compositeReg, OP_TYPE_POINTER); this->value = this->cc->createRegister(ot); GetSig *gs = new GetSig(pToSig, this->value, NULL); this->cc->addCode(gs); return this->value; } // not a signal if (this->value != NULL) { // value already present. return this->value; } // composite pointer referring to the location of a variable. // use an IndirectOperand and cache it in value assert(this->composite != NULL); Register *compositeReg = dynamic_cast(this->composite); if (compositeReg == NULL) { compositeReg = this->cc->createRegister(OP_TYPE_POINTER); Mov *toReg = new Mov(this->composite, compositeReg); this->cc->addCode(toReg); } IndirectOperand *ir = new IndirectOperand(compositeReg, ot); this->value = ir; return this->value; } Operand * RegisterSet::getDestination(enum BaseType bt) { assert(this->composite != NULL); enum OpType ot; if (this->isSignal) { // return a pointer to the concrete driver ot = OP_TYPE_POINTER; } else { ot = toOpType(bt); } Register *compositeReg = dynamic_cast(this->composite); if (compositeReg == NULL) { compositeReg = this->cc->createRegister(OP_TYPE_POINTER); Mov *m = new Mov(this->composite, compositeReg); this->cc->addCode(m); this->composite = compositeReg; } return new IndirectOperand(compositeReg, ot); } Operand * RegisterSet::getPointer(void) { assert(this->composite != NULL); return this->composite; } void RegisterSet::setPointer(Operand *ptr) { assert(ptr != NULL); util::MiscUtil::terminate(this->composite); util::MiscUtil::terminate(this->value); this->composite = ptr; } void RegisterSet::setValue(Operand *val) { assert(val != NULL); util::MiscUtil::terminate(this->composite); util::MiscUtil::terminate(this->value); this->value = val; } void RegisterSet::subscribe( TypeDeclaration *arrayType, std::list indices ) { assert(arrayType != NULL); ArrayHandling ah = ArrayHandling(arrayType, this->getPointer(), *this->cc, this->leftBounds, this->rightBounds, this->directions); Register *result = ah.subscribe(indices); this->setPointer(result); this->leftBounds.clear(); this->rightBounds.clear(); } void RegisterSet::setUnconstraintBounds( std::list lb, std::list rb, std::list ds ) { this->leftBounds = lb; this->rightBounds = rb; this->directions = ds; } bool RegisterSet::isUnconstraint(void) const { return ! this->leftBounds.empty(); } void RegisterSet::getConstraints( std::list &lb, std::list &rb, std::list &ds ) const { lb = this->leftBounds; rb = this->rightBounds; ds = this->directions; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/SimplifyExpressions.cpp0000664000175000017500000000407511266114422023070 0ustar potyrapotyra/* $Id: SimplifyExpressions.cpp 4824 2009-10-16 16:02:26Z potyra $ * * SimplifyExpressions: simplify nested expressions to simple expressions. * * Copyright (C) 2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/SimplifyExpressions.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/FunctionCall.hpp" namespace ast { void SimplifyExpressions::visit(Process &node) { this->simpleSeqs.clear(); assert(node.seqStats != NULL); this->listTraverse(*node.seqStats, this->simpleSeqs); /* TODO: pickup new declarations. node.declarations->push_back(FIXME); */ } void SimplifyExpressions::visit(VarAssignStat &node) { assert(node.source != NULL); assert(node.target != NULL); node.source->accept(*this); this->setNode(node.source); } void SimplifyExpressions::visit(SigAssignStat &node) { // FIXME } void SimplifyExpressions::visit(CondalSigAssign &node) { // must have been replaced already. assert(false); } void SimplifyExpressions::visit(FunctionCall &node) { // TODO } void SimplifyExpressions::setNode(Expression *&e) { if (this->repexp != NULL) { e = this->repexp; this->repexp = NULL; } } SimpleName * SimplifyExpressions::genTemporary( SubtypeIndication *type, std::string name, const char *suffix ) { if (name == "") { name = "tmp"; } if (suffix == NULL) { suffix = ""; } name = "__" + name + suffix; std::string *namep = new std::string(name); VarDeclaration *vd = new VarDeclaration( ValDeclaration::MODE_INOUT, namep, NULL, type, Location("simplified")); std::list cands = std::list(); Symbol *sym = new Symbol(namep, SYMBOL_VARIABLE, NULL, *vd); cands.push_back(sym); SimpleName *ret = new SimpleName( new std::string(name), cands, Location("simplified")); return ret; } } /* namespace ast */ fauhdlc-20130704/frontend/visitor/DotVisitor.hpp0000664000175000017500000003517211243477217021157 0ustar potyrapotyra/* $Id: DotVisitor.hpp 4555 2009-08-21 11:01:35Z potyra $ * DotVisitor: create a .dot graph representation of the abstract syntax * tree. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DOT_VISITOR_HPP_INCLUDED #define __DOT_VISITOR_HPP_INCLUDED #include #include "frontend/visitor/TopDownVisitor.hpp" namespace ast { //! convert AST to a dot graph. /** This visitor will convert the abstract syntax tree to a dot graph. * The output can then be converted to e.g. a postscript file with * dot -Tps output.dot > output.ps * This visitor is safe to be used during all frontend stages. */ class DotVisitor : public TopDownVisitor { public: //! c'tor DotVisitor(); //! d'tor ~DotVisitor(); private: /** visit a ElementAssociation * @param node node that get's visited. */ virtual void visit(ElementAssociation& node); /** visit a ConstInteger * @param node node that get's visited. */ virtual void visit(ConstInteger& node); /** visit a ConstReal * @param node node that get's visited. */ virtual void visit(ConstReal& node); /** visit a ConstArray * @param node node that get's visited. */ virtual void visit(ConstArray &node); /** visit a SimpleName * @param node node that get's visited. */ virtual void visit(SimpleName& node); /** visit a SelectedName * @param node node that get's visited. */ virtual void visit(SelectedName& node); /** visit a AttributeName * @param node node that get's visited. */ virtual void visit(AttributeName& node); /** visit a TemporaryName * @param node node that get's visited. */ virtual void visit(TemporaryName& node); /** Visit an Entity declaration. * @param node Entity Declaration node that get's visited. */ virtual void visit(Entity& node); /** Visit an Signal declaration. * @param node SignalDeclaration node that get's visited. */ virtual void visit(SignalDeclaration& node); /** Visit an Constant declaration. * @param node ConstantDeclaration node that get's visited. */ virtual void visit(ConstantDeclaration& node); /** Visit an FunctionCall. * @param node FunctionCall node that get's visited. */ virtual void visit(FunctionCall& node); /** Visit an IfStat. * @param node IfStat node that get's visited. */ virtual void visit(IfStat& node); /** Visit an NullStat. * @param node IfStat node that get's visited. */ virtual void visit(NullStat& node); /** Visit a ForLoopStat * @param node ForLoopStat node that get's visited. */ virtual void visit(ForLoopStat& node); /** Visit a WhileLoopStat * @param node WhileLoopStat node that get's visited. */ virtual void visit(WhileLoopStat& node); /** Visit a NextStat * @param node NextStat node that get's visited. */ virtual void visit(NextStat& node); /** Visit a VarAssignStat * @param node VarAssignStat node that get's visited. */ virtual void visit(VarAssignStat& node); /** Visit a WaitStat * @param node WaitStat node that get's visited. */ virtual void visit(WaitStat& node); /** Visit a ExitStat * @param node ExitStat node that get's visited. */ virtual void visit(ExitStat& node); /** Visit a SigAssignStat * @param node SigAssignStat node that get's visited. */ virtual void visit(SigAssignStat& node); /** Visit a WaveFormElem * @param node WaveFormElem node that get's visited. */ virtual void visit(WaveFormElem& node); /** Visit a ReturnStat * @param node ReturnStat node that get's visited. */ virtual void visit(ReturnStat& node); /** Visit a ProcCallStat * @param node ReturnStat node that get's visited. */ virtual void visit(ProcCallStat& node); /** Visit a AssertStat * @param node AssertStat node that get's visited. */ virtual void visit(AssertStat& node); /** Visit a VarDeclaration * @param node VarDeclaration node that get's visited. */ virtual void visit(VarDeclaration& node); /** Visit a DiscreteRange * @param node DiscreteRange node that get's visited. */ virtual void visit(DiscreteRange& node); /** Visit a CaseStat * @param node CaseStat node that get's visited. */ virtual void visit(CaseStat& node); /** Visit a CaseAlternative * @param node CaseAlternative node that get's visited. */ virtual void visit(CaseAlternative& node); /** Visit a Others node. * @param node Others node that get's visited. */ virtual void visit(Others& node); /** Visit a Architecture node. * @param node Architecture node that get's visited. */ virtual void visit(Architecture& node); /** Visit a AssociationElement node. * @param node AssociationElement node that get's visited. */ virtual void visit(AssociationElement& node); /** Visit a FunctionDeclaration node. * @param node FunctionDeclaration node that get's visited. */ virtual void visit(FunctionDeclaration& node); /** Visit a ProcedureDeclaration node. * @param node ProcedureDeclaration node that get's visited. */ virtual void visit(ProcedureDeclaration& node); /** Visit a CompInstStat node. * @param node CompInstStat node that get's visited. */ virtual void visit(CompInstStat& node); /** Visit a Package node. * @param node Package node that get's visited. */ virtual void visit(Package& node); /** Visit a PackageBody node. * @param node PackageBody node that get's visited. */ virtual void visit(PackageBody& node); /** Visit a Process node. * @param node Process node that get's visited. */ virtual void visit(Process& node); /** Visit a SubprogBody node. * @param node SubprogBody node that get's visited. */ virtual void visit(SubprogBody& node); /** Visit a CondalSigAssign node. * @param node CondalSigAssign node that get's visited. */ virtual void visit(CondalSigAssign& node); /** Visit an EnumerationType node. * @param node EnumerationType node that get's visited. */ virtual void visit(EnumerationType& node); /** Visit an PhysicalType node. * @param node PhysicalType node that get's visited. */ virtual void visit(PhysicalType& node); /** Visit an PhysicalTypeUnit node. * @param node PhysicalTypeUnit node that get's visited. */ virtual void visit(PhysicalTypeUnit& node); /** Visit an RangeConstraintType node. * @param node RangeConstraintType node that get's visited. */ virtual void visit(RangeConstraintType& node); /** Visit an UnconstrainedArrayType node. * @param node UnconstrainedArrayType node that get's visited. */ virtual void visit(UnconstrainedArrayType& node); /** Visit an RecordType node. * @param node RecordType node that get's visited. */ virtual void visit(RecordType& node); /** Visit an RecordTypeElement node. * @param node RecordTypeElement node that get's visited. */ virtual void visit(RecordTypeElement &node); /** Visit an Aggregate node. * @param node Aggregate node that get's visited. */ virtual void visit(Aggregate &node); /** Visit a SubtypeIndication node. * @param node SubtypeIndication node that get's visited. */ virtual void visit(SubtypeIndication &node); /** Visit a Library node. * @param node Library node that get's visited. */ virtual void visit(Library &node); /** Visit a LibraryList node. * @param node LibraryList node that get's visited. */ virtual void visit(LibraryList &node); /** Visit a Subscript node. * @param node Subscript node that get's visited. */ virtual void visit(Subscript &node); /** Visit a Slice node. * @param node Slice node that get's visited. */ virtual void visit(Slice &node); /** Visit a TypeConversion node. * @param node TypeConversion node that get's visited. */ virtual void visit(TypeConversion &node); /** Visit an AttributeDeclaration node. * @param node AttributeDeclaration node that gets visited. */ virtual void visit(AttributeDeclaration &node); /** Visit an AttributeSpecification node. * @param node AttributeSpecification node that gets visited. */ virtual void visit(AttributeSpecification &node); public: //! write the dot-graph to stream. /** @param stream to which the dot graph should get written to. */ void put(std::ostream &stream) const; private: using TopDownVisitor::process; //! Process a generic ValDeclaration. /** This function will get called for each ValDeclaration (or class * derived from ValDeclaration) that get's visited. * * @param node ValDeclaration instance. */ virtual void process(ValDeclaration& node); //! Process a generic SymbolDeclaration. /** This function will get called for each SymbolDeclaration (or class * derived from SymbolDeclaration) that get's visited. * * @param node SymbolDeclaration instance. */ virtual void process(SymbolDeclaration& node); //! Process a generic Expression. /** This function will get called for each Expression (or class * derived from Expression) that get's visited. * * @param node Expression instance. */ virtual void process(Expression& node); //! Process a generic SeqStat. /** This function will get called for each SeqStat (or class * derived from SeqStat) that get's visited. * * @param node SeqStat instance. */ virtual void process(SeqStat& node); //! Process a generic LoopStat. /** This function will get called for each LoopStat (or class * derived from LoopStat) that get's visited. * * @param node LoopStat instance. */ virtual void process(LoopStat& node); //! Process a generic ConditionedStat. /** This function will get called for each ConditionedStat (or class * derived from ConditionedStat) that get's visited. * * @param node ConditionedStat instance. */ virtual void process(ConditionedStat& node); //! Process a generic Callable. /** This function will get called for each Callable (or class * derived from Callable) that get's visited. * * @param node Callable instance. */ virtual void process(Callable& node); //! Process a generic LibUnit. /** This function will get called for each LibUnit (or class * derived from LibUnit) that get's visited. * * @param node LibUnit instance. */ virtual void process(LibUnit& node); //! Process a generic TypeDeclaration. /** This function will get called for each TypeDeclaration (or class * derived from TypeDeclaration) that get's visited. * * @param node TypeDeclaration instance. */ virtual void process(TypeDeclaration& node); //! Process a generic Name. /** This function will get called for each Name (or class * derived from Name) that get's visited. * * @param node Name instance. */ virtual void process(Name &node); //! Process a generic PrefixedName. /** This function will get called for each PrefixedName (or class * derived from PrefixedName) that get's visited. * * @param node PrefixedName instance. */ virtual void process(PrefixedName &node); /** one edge in the graph */ class Edge { public: /** @param source source number of node. * @param destination destination number of node. */ Edge( int source, int destination ) : from(source), to(destination), label(NULL) {} /** @param source source number of node. * @param destination destination number of node. * @param lbl label of the edge. */ Edge( int source, int destination, const char* lbl ) : from(source), to(destination), label(new std::string(lbl)) {} //! copy c'tor /** need to copy the string as well. * @param other other Edge instance */ Edge(const Edge& other) : from(other.from), to(other.to) { if (other.label) { this->label = new std::string(*other.label); } else { this->label = NULL; } } ~Edge(); /** put the edge to stream. * @param stream to which the edge should be written. */ void put(std::ostream& stream) const; private: /** origin of the edge */ int from; /** destination of the edge */ int to; /** optional label of the edge */ std::string* label; }; /** one description of a node. */ class NodeDescription { public: /** @param num unique number of the Description * @param n name of the node. */ NodeDescription(int num, std::string n) : id(num), name(n) {} /** add a name/value pair to the description. * @param n name of the name/value-pair. * @param value value of the name/value-pair. */ void add(std::string n, std::string value); /** add a simple string to the description. * @param s string to add. */ void add(std::string s); /** put the node to a stream. * @param stream stream on which the node should get written. */ void put(std::ostream& stream) const; /** unique number of the node. */ int id; private: /** name of the node. */ std::string name; /** list of attributes */ std::list attributes; }; /** generate edges for list of children. * @param fromId id of parent node. * @param l list of pointers to child nodes. */ template void makeEdges(int fromId, T l); /** generate edges for list of children. * @param fromId id of parent node. * @param l list of pointers to child nodes. * @param s label of the edge. */ template void makeEdges(int fromId, T l, const char* s); /** create a new node description, assign it an id and set it to be * the current description. * @param node currently visited AstNode. * @param desc descriptive string. * @return newly created NodeDescription. */ NodeDescription* makeDescription(AstNode& node, const char* desc); /** assign a new Id to an AstNode. * @param node node to which the number should get assigned to. * @return newly created id. */ int assignId(AstNode& node); /** edges of the graph */ std::list edges; /** node of the graph */ std::list nodes; /** last unique id that was handed out */ int idCounter; /** current NodeDescription */ NodeDescription* currentDesc; }; }; /* namespace ast */ #include "DotVisitor.tpp" #endif /* __DOT_VISITOR_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/LookupTypes.hpp0000664000175000017500000001015511305513466021335 0ustar potyrapotyra/* $Id: LookupTypes.hpp 4850 2009-12-02 16:35:02Z potyra $ * LookupTypes: find out the type of an AST node. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LOOKUP_TYPES_HPP_INCLUDED #define __LOOKUP_TYPES_HPP_INCLUDED #include "frontend/visitor/NullVisitor.hpp" #include "frontend/ast/AttributeDeclaration.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include namespace ast { /** class to determine the type of a symbol, inline implementation. */ class LookupTypes : public NullVisitor { public: //! c'tor /** @param doBaseLookups stop lookup at normal type or traverse to * base of the type? * @param doElementLookups also cross the boundary from Arrays to * array elements? */ LookupTypes( bool doBaseLookups, bool doElementLookups ) : declaration(NULL), baseLookup(doBaseLookups), elementLookup(doElementLookups) {} /** determined declaration, NULL if no type is known */ const TypeDeclaration *declaration; private: /** The following SymbolDeclarations are "not for us". */ virtual void visit(Library &node) {} virtual void process(SeqStat &node) {} virtual void process(ConcurrentStat &node) {} virtual void process(Callable &node) {} virtual void process(LibUnit &node) {} /** Visit an UnconstrainedArrayType node. * @param node UnconstrainedArrayType node that get's visited. */ virtual void visit(UnconstrainedArrayType &node) { if (this->elementLookup) { assert(node.elementType != NULL); node.elementType->accept(*this); } else { this->process(node); } } /** visit a TypeDeclaration * @param node the TypeDeclaration itself. */ virtual void process(TypeDeclaration &node) { this->declaration = &node; } //! visit a RecordTypeElement /** @param node RecordTypeElement */ virtual void visit(RecordTypeElement& node) { assert(node.subtype); if (this->baseLookup) { node.subtype->accept(*this); } else { this->declaration = node.subtype; } } //! process a ValDeclaration /** @param node ValDeclaration */ virtual void process(ValDeclaration &node) { assert(node.subtypeIndic); if (this->baseLookup) { node.subtypeIndic->accept(*this); } else { this->declaration = node.subtypeIndic; } } /** visit a PhysicalTypeUnit. * SimpleNames on the right hand side can mean a physical * literal w.o. number. * @param node PhysicalTypeUnit. */ virtual void visit(PhysicalTypeUnit &node) { // already at base type this->declaration = node.parent; assert(this->declaration != NULL); } /** visit a SubtypeIndication * @param node SubtypeIndication which is the type itself. */ virtual void visit(SubtypeIndication &node) { if (this->baseLookup) { // ugly const cast, nevermind though, since // the final const will be preserved. TypeDeclaration *t = const_cast( node.declaration); t->accept(*this); } else { this->declaration = &node; } } /** visit a FunctionDeclaration * @param node FunctionDeclaration, take result type. */ virtual void visit(FunctionDeclaration &node) { assert(node.returnType); if (this->baseLookup) { node.returnType->accept(*this); } else { this->declaration = node.returnType; } } virtual void visit(AttributeDeclaration &node) { assert(node.type != NULL); if (this->baseLookup) { TypeDeclaration *t = const_cast(node.type); t->accept(*this); } else { this->declaration = node.type; } } //! process a SymbolDeclaration /** @param node SymbolDeclaration */ virtual void process(SymbolDeclaration &node) { // must not happen, coming from a non-type SymbolDecl. assert(false); } /** lookup the base type, or is a SubtypeIndication enough? */ bool baseLookup; /** lookup spans to element types of Array types as well? */ bool elementLookup; }; }; /* namespace ast */ #endif /* __LOOKUP_TYPES_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GCLoops.hpp0000664000175000017500000001243111137610234020336 0ustar potyrapotyra/* $Id: GCLoops.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Generate intermediate code, loop specific parts. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GC_LOOPS_HPP_INCLUDED #define __GC_LOOPS_HPP_INCLUDED #include #include "intermediate/container/CodeContainer.hpp" #include "intermediate/operands/Operand.hpp" #include "frontend/ast/LoopStat.hpp" namespace ast { //! generic class to iterate in a while loop manner /** This class can be used to generate code in a while-loop like manner. * high level semantics: * * initializeCounter(); * while (checkCondition()) { * loopBody(); * incCounter(); * } * * if/goto pseudo-code: * * initializeCounter(); * loopCheck: * if ! checkCondition() goto loopDone * loopBody(); * loopInc: * loopInc(); * goto loopCheck; * loopDone: */ class WhileIterate { public: //! c'tor /** @param container current code container to add code to. */ WhileIterate(intermediate::CodeContainer &container); //! dummy d'tor virtual ~WhileIterate(); //! generate code for the iteration /** not meant to be overloaded. */ void addIteration(void); protected: //! generate code to initialize the counter virtual void initializeCounter(void) = 0; //! generate code to check the condition /** in case the condition is false, jump to loopDone to exit the * loop. */ virtual void checkCondition(void) = 0; //! generate code for the loop body /** the following labels can be used: * loopInc for a continue semantic * loopDone for a break semantic */ virtual void loopBody(void) = 0; //! generate code to increase the counter virtual void incCounter(void) = 0; //! CodeContainer to add generated code to. intermediate::CodeContainer &cc; public: /** Label after which the counters are increased * jump here from the body, to implement a continue semantic. */ intermediate::Label *loopInc; /** Label when the loop has finished. * jump here from the body, to implement a break semantic. */ intermediate::Label *loopDone; private: //! generate code for the iteration. /** Here, the iteration scheme is defined. Basically, this is just * a call from addIteration, only enforcing that the iteration scheme * is not to be modified in subclasses. */ void genIterateCode(void); //! Label of the loop condition intermediate::Label *loopCheck; }; //! iterate over a for statement. class ForLoopIterate : public WhileIterate { public: //! c'tor /** @param condition code container to append generated code to. * @param counter Operand referring to the loop induction variable. * @param initializer Operand containing the initial counter value. * @param rightBound right bound of the loop (not necessary upper * bound). * @param isAscending true, if the loop is a "TO" loop, false for a * "DOWNTO" loop. */ ForLoopIterate( intermediate::CodeContainer &container, intermediate::Operand &counter, intermediate::Operand &initializer, intermediate::Operand &rightBound, bool isAscending ) : WhileIterate(container), cnt(counter), init(initializer), rbound(rightBound), isAsc(isAscending) {} protected: //! generate code to initialize the counter virtual void initializeCounter(void); //! generate code to check the condition /** in case the condition is false, jump to loopDone to exit the * loop. */ virtual void checkCondition(void); //! generate code to increase the counter virtual void incCounter(void); //! counter operand. intermediate::Operand &cnt; //! initial value of the counter. intermediate::Operand &init; //! right bound of the loop (inclusive) intermediate::Operand &rbound; //! is the loop ascending? bool isAsc; }; //! registry containing a mapping between LoopStat AST nodes and WhileIterate /** This registry can be used to lookup intermediate code loop iterations from * next and exit statements. */ class LoopRegistry { public: /** remember a loop statement with the corresponding iterate class. * @param node AST node * @param iterate corresponding iterate instance. */ void rememberLoop(LoopStat *node, WhileIterate *iterate) { this->knownLoops[node] = iterate; } /** forget a mapping between loop statement and corresponding iterate * class. * @param node loop statement node to forget. */ void forgetLoop(LoopStat *node) { std::map::iterator i = this->knownLoops.find(node); assert(i != this->knownLoops.end()); this->knownLoops.erase(i); } /** lookup the corresponding iterate instance to a loop statement. * @param node AST loop node for which the corresponding entry should * get looked up. * @return corresponding entry. */ WhileIterate *lookup(LoopStat *node) const { std::map::const_iterator i = this->knownLoops.find(node); assert(i != this->knownLoops.end()); return i->second; } private: //! mapping between AST loop statements and iterate instances. std::map knownLoops; }; }; /* namespace ast */ #endif /* __GC_LOOPS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/WaitConditions.cpp0000664000175000017500000000572511137610234021771 0ustar potyrapotyra/* $Id: WaitConditions.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Wait conditions: Checks sensitivity lists and wait statements, and * transforms sensitivity lists into wait statements. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/WaitConditions.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "frontend/reporting/ErrorRegistry.hpp" namespace ast { WaitConditions::WaitConditions() : sensList(NULL), waitSeen(false) { } void WaitConditions::visit(Process &node) { // wait statement AND sensitivityList -> ERROR // no wait statement AND sensitivityList empty -> WARNING // // semantics of a wait: // time := now() + timeout // loop // trigger(self, time) // trigger_sig(self, signal_list) // suspend() // time1 := now() // exit if time1 >= time -- timeout // exit if condition -- condition met // end loop this->sensList = node.sensitivityList; this->waitSeen = false; if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); } if ((this->sensList == NULL) && (! this->waitSeen)) { std::string msg = ""; if (node.name != NULL) { msg += *node.name; msg += " "; } msg += "contains no wait statement, possible infinite loop"; CompileError *ce = new CompileError(node, msg); ErrorRegistry::addWarning(ce); } if ((this->sensList != NULL) && (! this->waitSeen)) { assert(! this->sensList->empty()); WaitStat *ws = new WaitStat(this->sensList, NULL, NULL, this->sensList->front()->location); if (node.seqStats == NULL) { node.seqStats = new std::list(); } node.seqStats->push_back(ws); } this->sensList = NULL; this->waitSeen = false; node.sensitivityList = NULL; } void WaitConditions::visit(WaitStat &node) { this->waitSeen = true; if (this->sensList != NULL) { CompileError *ce = new CompileError(node, "Wait statement and sensitivity list present."); ErrorRegistry::addError(ce); } // TODO construct sensitivity list if empty from condition. (LRM 8.1) } void WaitConditions::visit(ProcCallStat &node) { assert(node.definition != NULL); if (node.definition->containsWait) { this->waitSeen = true; if (this->sensList != NULL) { CompileError *ce = new CompileError(node, "Wait statement via procedure call, but " "sensitivity list present."); ErrorRegistry::addError(ce); } } } void WaitConditions::visit(ProcedureDeclaration &node) { if (node.definition != NULL) { this->sensList = NULL; this->waitSeen = false; node.definition->accept(*this); node.containsWait = this->waitSeen; this->waitSeen = false; } } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/Visitor.hpp0000664000175000017500000003645211266056227020511 0ustar potyrapotyra/* $Id: Visitor.hpp 4821 2009-10-16 11:44:23Z potyra $ * * Visitor: base class for all visitors. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __VISITOR_HPP_INCLUDED #define __VISITOR_HPP_INCLUDED namespace ast { /* cannot use includes here due to circular include problem, so * forward define all nodes. */ class AstNode; class ElementAssociation; class ConstInteger; class ConstReal; class ConstArray; class Entity; class SymbolDeclaration; class ValDeclaration; class SignalDeclaration; class ConstantDeclaration; class Expression; class SeqStat; class IfStat; class NullStat; class LoopStat; class ForLoopStat; class WhileLoopStat; class NextStat; class VarAssignStat; class WaitStat; class ExitStat; class ConditionedStat; class SigAssignStat; class WaveFormElem; class ReturnStat; class ProcCallStat; class AssertStat; class VarDeclaration; class DiscreteRange; class CaseStat; class CaseAlternative; class Others; class Architecture; class AssociationElement; class Callable; class FunctionDeclaration; class ProcedureDeclaration; class CompInstStat; class LibUnit; class Package; class PackageBody; class Process; class SubprogBody; class CondalSigAssign; class TypeDeclaration; class EnumerationType; class PhysicalType; class PhysicalTypeUnit; class RangeConstraintType; class UnconstrainedArrayType; class RecordType; class RecordTypeElement; class Aggregate; class FunctionCall; class Name; class SubtypeIndication; class Library; class LibraryList; class Subscript; class Slice; class TypeConversion; class TemporaryName; class SimpleName; class AttributeName; class SelectedName; class PrefixedName; class AttributeDeclaration; class AttributeSpecification; class AttributableDeclaration; class ConcurrentStat; //! Generic interface for AST vistitors. /** This is an abstract base class for all AST visitors. */ class Visitor { public: /* all non leaf nodes in the AST class hierarchy * (i.e. all nodes, that might get directly instantiated) * will get their visit method. */ /** d'tor, not used in interface. */ virtual ~Visitor() {} /** visit an ElementAssociation * @param node node that gets visited. */ virtual void visit(ElementAssociation &node) = 0; /** visit a ConstInteger * @param node node that gets visited. */ virtual void visit(ConstInteger &node) = 0; /** visit a ConstReal * @param node node that gets visited. */ virtual void visit(ConstReal &node) = 0; /** visit a ConstArray * @param node node that gets visited. */ virtual void visit(ConstArray &node) = 0; /** Visit an Entity declaration. * @param node Entity Declaration node that gets visited. */ virtual void visit(Entity &node) = 0; /** Visit an Signal declaration. * @param node SignalDeclaration node that gets visited. */ virtual void visit(SignalDeclaration &node) = 0; /** Visit an Constant declaration. * @param node ConstantDeclaration node that gets visited. */ virtual void visit(ConstantDeclaration &node) = 0; /** Visit an FunctionCall. * @param node FunctionCall node that gets visited. */ virtual void visit(FunctionCall &node) = 0; /** Visit an IfStat. * @param node IfStat node that gets visited. */ virtual void visit(IfStat &node) = 0; /** Visit a NullStat. * @param node NullStat node that gets visited. */ virtual void visit(NullStat &node) = 0; /** Visit a ForLoopStat * @param node ForLoopStat node that gets visited. */ virtual void visit(ForLoopStat &node) = 0; /** Visit a WhileLoopStat * @param node WhileLoopStat node that gets visited. */ virtual void visit(WhileLoopStat &node) = 0; /** Visit a NextStat * @param node NextStat node that gets visited. */ virtual void visit(NextStat &node) = 0; /** Visit a VarAssignStat * @param node VarAssignStat node that gets visited. */ virtual void visit(VarAssignStat &node) = 0; /** Visit a WaitStat * @param node WaitStat node that gets visited. */ virtual void visit(WaitStat &node) = 0; /** Visit a ExitStat * @param node ExitStat node that gets visited. */ virtual void visit(ExitStat &node) = 0; /** Visit a SigAssignStat * @param node SigAssignStat node that gets visited. */ virtual void visit(SigAssignStat &node) = 0; /** Visit a WaveFormElem * @param node WaveFormElem node that gets visited. */ virtual void visit(WaveFormElem &node) = 0; /** Visit a ReturnStat * @param node ReturnStat node that gets visited. */ virtual void visit(ReturnStat &node) = 0; /** Visit a ProcCallStat * @param node ProcCallStat node that gets visited. */ virtual void visit(ProcCallStat &node) = 0; /** Visit a AssertStat * @param node AssertStat node that gets visited. */ virtual void visit(AssertStat &node) = 0; /** Visit a VarDeclaration * @param node VarDeclaration node that gets visited. */ virtual void visit(VarDeclaration &node) = 0; /** Visit a DiscreteRange * @param node DiscreteRange node that gets visited. */ virtual void visit(DiscreteRange &node) = 0; /** Visit a CaseStat * @param node CaseStat node that gets visited. */ virtual void visit(CaseStat &node) = 0; /** Visit a CaseAlternative * @param node CaseAlternative node that gets visited. */ virtual void visit(CaseAlternative &node) = 0; /** Visit a Others node. * @param node Others node that gets visited. */ virtual void visit(Others &node) = 0; /** Visit a Architecture node. * @param node Architecture node that gets visited. */ virtual void visit(Architecture &node) = 0; /** Visit a AssociationElement node. * @param node AssociationElement node that gets visited. */ virtual void visit(AssociationElement &node) = 0; /** Visit a FunctionDeclaration node. * @param node FunctionDeclaration node that gets visited. */ virtual void visit(FunctionDeclaration &node) = 0; /** Visit a ProcedureDeclaration node. * @param node ProcedureDeclaration node that gets visited. */ virtual void visit(ProcedureDeclaration &node) = 0; /** Visit a CompInstStat node. * @param node CompInstStat node that gets visited. */ virtual void visit(CompInstStat &node) = 0; /** Visit a Package node. * @param node Package node that gets visited. */ virtual void visit(Package &node) = 0; /** Visit a PackageBody node. * @param node PackageBody node that gets visited. */ virtual void visit(PackageBody &node) = 0; /** Visit a Process node. * @param node Process node that gets visited. */ virtual void visit(Process &node) = 0; /** Visit a SubprogBody node. * @param node SubprogBody node that gets visited. */ virtual void visit(SubprogBody &node) = 0; /** Visit a CondalSigAssign node. * @param node CondalSigAssign node that gets visited. */ virtual void visit(CondalSigAssign &node) = 0; /** Visit an EnumerationType node. * @param node EnumerationType node that gets visited. */ virtual void visit(EnumerationType &node) = 0; /** Visit an PhysicalType node. * @param node PhysicalType node that gets visited. */ virtual void visit(PhysicalType &node) = 0; /** Visit an PhysicalTypeUnit node. * @param node PhysicalTypeUnit node that gets visited. */ virtual void visit(PhysicalTypeUnit &node) = 0; /** Visit an RangeConstraintType node. * @param node RangeConstraintType node that gets visited. */ virtual void visit(RangeConstraintType &node) = 0; /** Visit an UnconstrainedArrayType node. * @param node UnconstrainedArrayType node that gets visited. */ virtual void visit(UnconstrainedArrayType &node) = 0; /** Visit an RecordType node. * @param node RecordType node that gets visited. */ virtual void visit(RecordType &node) = 0; /** Visit an RecordTypeElement node. * @param node RecordTypeElement node that gets visited. */ virtual void visit(RecordTypeElement &node) = 0; /** Visit an Aggregate node. * @param node Aggregate node that gets visited. */ virtual void visit(Aggregate &node) = 0; /** Visit a SubtypeIndication node. * @param node SubtypeIndication node that gets visited. */ virtual void visit(SubtypeIndication &node) = 0; /** Visit a Library node. * @param node Library node that gets visited. */ virtual void visit(Library& node) = 0; /** Visit a LibraryList node. * @param node LibraryList node that gets visited. */ virtual void visit(LibraryList& node) = 0; /** Visit a Subscript node. * @param node Subscript node that gets visited. */ virtual void visit(Subscript& node) = 0; /** Visit a Slice node. * @param node Slice node that gets visited. */ virtual void visit(Slice& node) = 0; /** Visit a TypeConversion node. * @param node TypeConversion node that gets visited. */ virtual void visit(TypeConversion &node) = 0; /** Visit a SimpleName node. * @param node TemporaryName node that gets visited. */ virtual void visit(SimpleName &node) = 0; /** Visit a TemporaryName node. * @param node TemporaryName node that gets visited. */ virtual void visit(TemporaryName &node) = 0; /** Visit an AttributeName node. * @param node AttributeName node that gets visited. */ virtual void visit(AttributeName &node) = 0; /** Visit a SelectedName node. * @param node SelectedName node that gets visited. */ virtual void visit(SelectedName &node) = 0; /** Visit an AttributeDeclaration node. * @param node AttributeDeclaration node that gets visited. */ virtual void visit(AttributeDeclaration &node) = 0; /** Visit an AttributeSpecification node. * @param node AttributeSpecification node that gets visited. */ virtual void visit(AttributeSpecification &node) = 0; protected: //! Process a generic AstNode. /** This function will get called for each AstNode * that gets visited. * * @param node AstNode */ virtual void process(AstNode &node) {} //! Process a generic ValDeclaration. /** This function will get called for each ValDeclaration (or class * derived from ValDeclaration) that gets visited. * * @param node ValDeclaration instance. */ virtual void process(ValDeclaration &node) {} //! Process a generic SymbolDeclaration. /** This function will get called for each SymbolDeclaration (or class * derived from SymbolDeclaration) that gets visited. * * @param node SymbolDeclaration instance. */ virtual void process(SymbolDeclaration &node) {} //! Process a generic Expression. /** This function will get called for each Expression (or class * derived from Expression) that gets visited. * * @param node Expression instance. */ virtual void process(Expression &node) {} //! Process a generic SeqStat. /** This function will get called for each SeqStat (or class * derived from SeqStat) that gets visited. * * @param node SeqStat instance. */ virtual void process(SeqStat &node) {} //! Process a generic LoopStat. /** This function will get called for each LoopStat (or class * derived from LoopStat) that gets visited. * * @param node LoopStat instance. */ virtual void process(LoopStat &node) {} //! Process a generic ConditionedStat. /** This function will get called for each ConditionedStat (or class * derived from ConditionedStat) that gets visited. * * @param node ConditionedStat instance. */ virtual void process(ConditionedStat &node) {} //! Process a generic Callable. /** This function will get called for each Callable (or class * derived from Callable) that gets visited. * * @param node Callable instance. */ virtual void process(Callable &node) {} //! Process a generic LibUnit. /** This function will get called for each LibUnit (or class * derived from LibUnit) that gets visited. * * @param node LibUnit instance. */ virtual void process(LibUnit &node) {} //! Process a generic TypeDeclaration. /** This function will get called for each TypeDeclaration (or class * derived from TypeDeclaration) that gets visited. * * @param node TypeDeclaration instance. */ virtual void process(TypeDeclaration &node) {} //! Process a generic PrefixedName. /** This function will get called for each PrefixedName (or class * derived from PrefixedName) that gets visited. * * @param node PrefixedName instance. */ virtual void process(PrefixedName &node) {} //! Process a generic Name. /** This function will get called for each Name (or class * derived from Name) that gets visited. * * @param node Name instance. */ virtual void process(Name &node) {} //! Process a AttributableDeclaration. /** This function will get called for each AttributableDeclaration * (or class derived from it) that gets visited. * * @param node AttributableDeclaration instance. */ virtual void process(AttributableDeclaration &node) {} //! traverse a list of AST nodes. /** This template function traverses a list of AST nodes. * You can only instantiate this with a T=std::list (or * list's of classes derived from AstNodes. * @param l list of AST nodes that should get traversed. */ template void listTraverse(const T &l); //! traverse a list of AST nodes, eventually deleting a node. /** This template function traverses a list of AST nodes. * You can only instantiate this with a T=std::list (or * list's of classes derived from AstNodes.) * @param l list of AST nodes that should get traversed. * @param deleteFlag after a node has been visited, deleteFlag will * be checked and if it is true, the last visited node * will get deleted from the list and deleteFlag gets * reset to false. */ template void listTraverse(T &l, bool &deleteFlag); //! traverse a list of AST nodes, eventually replacing a node. /** This template function traverses a list of AST nodes. * If replaceFlag is true, the current traversed item is * replaced by the contents of replace. * @param l std::list to traverse * @param replaceFlag if set to true, the current node * will get replaced with replace. Will be set to * false after node has been replaced. * @param replace list with nodes to replace the current * node. Will get cleared after the node has * been replaced. */ template void listTraverse(T &l, bool &replaceFlag, T &replace); //! traverse a list of AST nodes, eventually inserting a node. /** This template function traverses a list of AST nodes. * The nodes in insert will be inserted before the * last traversed node, and insert will be cleared. * @param l list to traverse * @param insert list to insert. */ template void listTraverse(T &l, T &insert); }; }; /* namespace ast */ // template definitions #include "frontend/visitor/Visitor.tpp" #endif /* __AST_VISITOR_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/TopDownVisitor.cpp0000664000175000017500000003674511305513466022021 0ustar potyrapotyra/* $Id: TopDownVisitor.cpp 4850 2009-12-02 16:35:02Z potyra $ * TopDownVisitor: Base class of Visitors that need a standard (top-down) * traversal. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include "frontend/visitor/TopDownVisitor.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/ConstArray.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/IfStat.hpp" #include "frontend/ast/NullStat.hpp" #include "frontend/ast/ForLoopStat.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/NextStat.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/ExitStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/WaveFormElem.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/AssertStat.hpp" #include "frontend/ast/VarDeclaration.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/CaseStat.hpp" #include "frontend/ast/CaseAlternative.hpp" #include "frontend/ast/Others.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/PackageBody.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/SubprogBody.hpp" #include "frontend/ast/CondalSigAssign.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/ElementAssociation.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/ast/Library.hpp" #include "frontend/ast/LibraryList.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/TypeConversion.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/AttributeDeclaration.hpp" #include "frontend/ast/AttributeSpecification.hpp" namespace ast { int TopDownVisitor::visits = 0; TopDownVisitor::TopDownVisitor() { TopDownVisitor::visits += 1; } void TopDownVisitor::visit(ElementAssociation &node) { this->process(node); if (node.choices != NULL) { this->listTraverse(*node.choices); } if (node.actual != NULL) { node.actual->accept(*this); } } void TopDownVisitor::visit(ConstInteger &node) { //FIXME this->process(node); } void TopDownVisitor::visit(ConstReal &node) { this->process(node); } void TopDownVisitor::visit(ConstArray &node) { this->process(node); for (std::vector::iterator i = node.elements->begin(); i != node.elements->end(); i++) { (*i)->accept(*this); } } void TopDownVisitor::visit(SimpleName &node) { this->process(node); } void TopDownVisitor::visit(SelectedName &node) { this->process(node); } void TopDownVisitor::visit(AttributeName &node) { this->process(node); } void TopDownVisitor::visit(TemporaryName &node) { this->process(node); } void TopDownVisitor::visit(Entity& node) { this->process(node); /* traverse generics */ if (node.generics != NULL) { this->listTraverse(*node.generics); } /* traverse ports */ if (node.ports != NULL) { this->listTraverse(*node.ports); } } void TopDownVisitor::visit(SignalDeclaration& node) { this->process(node); } void TopDownVisitor::visit(ConstantDeclaration& node) { this->process(node); } void TopDownVisitor::visit(FunctionCall& node) { this->process(node); if (node.subprog) { node.subprog->accept(*this); } if (node.arguments) { this->listTraverse(*node.arguments); } } void TopDownVisitor::visit(IfStat &node) { this->process(node); if (node.thenStats) { this->listTraverse(*node.thenStats); } if (node.elseStats) { this->listTraverse(*node.elseStats); } } void TopDownVisitor::visit(NullStat& node) { this->process(node); } void TopDownVisitor::visit(ForLoopStat &node) { this->process(node); if (node.loopVariable != NULL) { node.loopVariable->accept(*this); } /* traverse to discrete range */ if (node.range != NULL) { node.range->accept(*this); } } void TopDownVisitor::visit(WhileLoopStat &node) { this->process(node); /* traverse condition */ if (node.condition) { node.condition->accept(*this); } } void TopDownVisitor::visit(NextStat &node) { this->process(node); } void TopDownVisitor::visit(VarAssignStat& node) { this->process(node); /* traverse to target */ if (node.target) { node.target->accept(*this); } /* traverse to source */ if (node.source) { node.source->accept(*this); } } void TopDownVisitor::visit(WaitStat& node) { this->process(node); /* traverse to Sensitivity list */ if (node.sensitivities) { this->listTraverse(*node.sensitivities); } /* traverse to timeout */ if (node.timeout) { node.timeout->accept(*this); } } void TopDownVisitor::visit(ExitStat& node) { this->process(node); } void TopDownVisitor::visit(SigAssignStat& node) { this->process(node); /* traverse to target */ if (node.target != NULL) { node.target->accept(*this); } /* traverse to waveForm */ if (node.waveForm != NULL) { this->listTraverse(*node.waveForm); } } void TopDownVisitor::visit(WaveFormElem& node) { this->process(node); /* traverse to value */ if (node.value != NULL) { node.value->accept(*this); } /* traverse to delay */ if (node.delay != NULL) { node.delay->accept(*this); } } void TopDownVisitor::visit(ReturnStat& node) { this->process(node); /* traverse to result */ if (node.result != NULL) { node.result->accept(*this); } } void TopDownVisitor::visit(ProcCallStat& node) { this->process(node); /* traverse to arguments */ if (node.arguments != NULL) { this->listTraverse(*node.arguments); } /* traverse to referring symbol */ if (node.subprog != NULL) { node.subprog->accept(*this); } } void TopDownVisitor::visit(AssertStat& node) { this->process(node); /* traverse to report expression */ if (node.report != NULL) { node.report->accept(*this); } /* traverse to severity expression */ if (node.severity != NULL) { node.severity->accept(*this); } } void TopDownVisitor::visit(VarDeclaration& node) { this->process(node); } void TopDownVisitor::visit(DiscreteRange& node) { this->process(node); /* traverse to from */ if (node.from != NULL) { node.from->accept(*this); } /* traverse to */ if (node.to != NULL) { node.to->accept(*this); } } void TopDownVisitor::visit(CaseStat& node) { this->process(node); /* traverse to select */ if (node.select != NULL) { node.select->accept(*this); } /* traverse to alternatives */ if (node.alternatives != NULL) { this->listTraverse(*node.alternatives); } } void TopDownVisitor::visit(CaseAlternative& node) { this->process(node); /* traverse to isVals */ if (node.isVals != NULL) { this->listTraverse(*node.isVals); } /* traverse to thenStats */ if (node.thenStats != NULL) { this->listTraverse(*node.thenStats); } } void TopDownVisitor::visit(Others &node) { this->process(node); } void TopDownVisitor::visit(Architecture &node) { this->process(node); /* traverse to concurrentStats */ if (node.concurrentStats != NULL) { this->listTraverse(*node.concurrentStats); } } void TopDownVisitor::visit(AssociationElement& node) { this->process(node); /* traverse to formalPart */ if (node.formal != NULL) { node.formal->accept(*this); } /* traverse to actual */ if (node.actual != NULL) { node.actual->accept(*this); } } void TopDownVisitor::visit(FunctionDeclaration& node) { this->process(node); if (node.returnType != NULL) { node.returnType->accept(*this); } } void TopDownVisitor::visit(ProcedureDeclaration& node) { this->process(node); } void TopDownVisitor::visit(CompInstStat& node) { this->process(node); /* traverse to entityName */ if (node.entityName != NULL) { node.entityName->accept(*this); } /* traverse to genericMap */ if (node.genericMap != NULL) { this->listTraverse(*node.genericMap); } /* traverse to portMap */ if (node.portMap != NULL) { this->listTraverse(*node.portMap); } } void TopDownVisitor::visit(Package& node) { this->process(node); if (node.body != NULL) { node.body->accept(*this); } } void TopDownVisitor::visit(PackageBody& node) { this->process(node); } void TopDownVisitor::visit(Process &node) { this->process(node); if (node.sensitivityList != NULL) { this->listTraverse(*node.sensitivityList); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); } if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); } } void TopDownVisitor::visit(SubprogBody& node) { this->process(node); if (node.declarations != NULL) { this->listTraverse(*node.declarations); } if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); } } void TopDownVisitor::visit(CondalSigAssign& node) { this->process(node); if (node.target != NULL) { node.target->accept(*this); } if (node.assignStat != NULL) { node.assignStat->accept(*this); } } void TopDownVisitor::visit(EnumerationType& node) { this->process(node); } void TopDownVisitor::visit(PhysicalType& node) { this->process(node); if (node.constraint != NULL) { node.constraint->accept(*this); } if (node.units != NULL) { this->listTraverse(*node.units); } } void TopDownVisitor::visit(PhysicalTypeUnit& node) { this->process(node); if (node.physUnit != NULL) { node.physUnit->accept(*this); } } void TopDownVisitor::visit(RangeConstraintType& node) { this->process(node); if (node.constraint != NULL) { node.constraint->accept(*this); } } void TopDownVisitor::visit(UnconstrainedArrayType& node) { this->process(node); if (node.indexTypes != NULL) { this->listTraverse(*node.indexTypes); } if (node.elementType != NULL) { node.elementType->accept(*this); } } void TopDownVisitor::visit(RecordType& node) { this->process(node); if (node.elements != NULL) { this->listTraverse(*(node.elements)); } } void TopDownVisitor::visit(RecordTypeElement& node) { this->process(node); if (node.subtype) { node.subtype->accept(*this); } } void TopDownVisitor::visit(Aggregate& node) { this->process(node); if (node.associations) { this->listTraverse(*node.associations); } } void TopDownVisitor::visit(SubtypeIndication& node) { this->process(node); if (node.typeName) { node.typeName->accept(*this); } if (node.constraint) { node.constraint->accept(*this); } if (node.indexConstraint != NULL) { this->listTraverse(*node.indexConstraint); } } void TopDownVisitor::visit(Library& node) { this->process(node); this->listTraverse(node.units); } void TopDownVisitor::visit(LibraryList& node) { this->process(node); this->listTraverse(node.libraries); } void TopDownVisitor::visit(Subscript& node) { this->process(node); if (node.source) { node.source->accept(*this); } } void TopDownVisitor::visit(Slice &node) { this->process(node); if (node.source) { node.source->accept(*this); } if (node.range) { node.range->accept(*this); } } void TopDownVisitor::visit(TypeConversion &node) { this->process(node); if (node.source) { node.source->accept(*this); } } void TopDownVisitor::visit(AttributeDeclaration &node) { this->process(node); } void TopDownVisitor::visit(AttributeSpecification &node) { this->process(node); assert(node.init != NULL); node.init->accept(*this); } void TopDownVisitor::process(AstNode &node) { } void TopDownVisitor::process(ValDeclaration& node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ SymbolDeclaration& sNode = static_cast(node); this->process(sNode); /* traverse to initializer */ if (node.init != NULL) { node.init->accept(*this); } /* traverse to subtype indic */ if (node.subtypeIndic != NULL) { node.subtypeIndic->accept(*this); } } void TopDownVisitor::process(SymbolDeclaration& node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ AstNode& aNode = static_cast(node); this->process(aNode); } void TopDownVisitor::process(Expression& node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ AstNode& aNode = static_cast(node); this->process(aNode); } void TopDownVisitor::process(SeqStat& node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ AstNode& anode = static_cast(node); this->process(anode); } void TopDownVisitor::process(LoopStat& node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ SeqStat& snode = static_cast(node); this->process(snode); /* taverse to loopStats */ if (node.loopStats != NULL) { this->listTraverse(*node.loopStats); } } void TopDownVisitor::process(ConditionedStat& node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ SeqStat& snode = static_cast(node); this->process(snode); /* taverse to condition */ if (node.condition != NULL) { node.condition->accept(*this); } } void TopDownVisitor::process(Callable &node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ SymbolDeclaration& snode = static_cast(node); this->process(snode); /* taverse to arguments */ if (node.arguments != NULL) { this->listTraverse(*node.arguments); } /* traverse to definition */ if (node.definition != NULL) { node.definition->accept(*this); } } void TopDownVisitor::process(LibUnit &node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ AttributableDeclaration& snode = static_cast(node); this->process(snode); /* taverse to useClauses */ if (node.useClauses != NULL) { this->listTraverse(*node.useClauses); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); } } void TopDownVisitor::process(TypeDeclaration& node) { /* up one class in hierarchy... this cast must never fail, or the * class hierarchy is wrong. */ SymbolDeclaration& snode = static_cast(node); this->process(snode); } void TopDownVisitor::process(Name &node) { Expression &e = static_cast(node); this->process(e); } void TopDownVisitor::process(PrefixedName &node) { Name &n = static_cast(node); this->process(n); if (node.prefix) { node.prefix->accept(*this); } } void TopDownVisitor::process(AttributableDeclaration &node) { SymbolDeclaration &snode = static_cast(node); this->process(snode); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/ResolveAggregates.cpp0000664000175000017500000001136511137610234022441 0ustar potyrapotyra/* $Id: ResolveAggregates.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Resolve ranges of positional and named aggregates. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/ResolveAggregates.hpp" #include #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/Others.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/reporting/ErrorRegistry.hpp" namespace ast { ResolveAggregates::ResolveAggregates( const DiscreteRange &arrayRange ) : haveOthers(false), named(false), positional(false), othersErrorReported(false), currentRange(NULL), sequencer(arrayRange) { } ResolveAggregates::~ResolveAggregates() { } void ResolveAggregates::visit(Aggregate &node) { assert(node.associations != NULL); this->haveOthers = false; this->named = false; this->positional = false; for (std::list::iterator i = node.associations->begin(); i != node.associations->end(); i++) { (*i)->accept(*this); } if (this->named && this->positional) { CompileError *ce = new CompileError(node, "Mixing named with positional association."); ErrorRegistry::addError(ce); return; } if (! this->sequencer.rs.empty()) { std::string s = std::string("Indices not covered by aggregate: "); s += util::MiscUtil::toString(this->sequencer.rs); CompileError *ce = new CompileError(node, s); ErrorRegistry::addError(ce); } } void ResolveAggregates::visit(ElementAssociation &node) { if (this->haveOthers) { // element after an "others" element not allowed. if (! this->othersErrorReported) { this->othersErrorReported = true; CompileError *ce = new CompileError(node, "Associaion after Others."); ErrorRegistry::addError(ce); } return; } if (node.choices == NULL) { // positional association this->positional = true; if (this->sequencer.rs.empty()) { CompileError *ce = new CompileError(node, "Index out of range."); ErrorRegistry::addError(ce); return; } universal_integer val = this->sequencer.getNext(); node.range = new RangeSet(val, val); return; } // node.choices != NULL: either named or others this->listTraverse(*node.choices); if (this->haveOthers) { if (node.choices->size() > 1) { // others mixed with elements. CompileError *ce = new CompileError(node, "Others in wrong place."); ErrorRegistry::addError(ce); this->currentRange = NULL; return; } // only one others element. set the Range by it. node.range = this->sequencer.getRemainder(); // all elements have been consumed by others. clear sequencer this->sequencer.rs.clear(); return; } this->named = true; node.range = this->currentRange; this->currentRange = NULL; } void ResolveAggregates::visit(Others &node) { if (this->haveOthers) { CompileError *ce = new ast::CompileError(node, "Duplicate others choice."); ErrorRegistry::addError(ce); } this->haveOthers = true; } void ResolveAggregates::visit(ConstInteger &node) { if (this->currentRange == NULL) { this->currentRange = new RangeSet(node.value, node.value); } else { this->currentRange->plus(node.value, node.value); } bool ret = this->sequencer.rs.minus(node.value, node.value); if (! ret) { CompileError *ce = new CompileError(node, "Aggregate range doesn't fit array range."); ErrorRegistry::addError(ce); } } void ResolveAggregates::visit(DiscreteRange &node) { if (this->currentRange == NULL) { this->currentRange = new RangeSet(node); } else { this->currentRange->plus(node); } bool ret = this->sequencer.rs.minus(node); if (! ret) { CompileError *ce = new CompileError(node, "Aggregate index doesn't fit array range."); ErrorRegistry::addError(ce); } } void ResolveAggregates::process(AstNode &node) { CompileError *ce = new CompileError(node, "Aggregate range/index not locally static."); ErrorRegistry::addError(ce); } /* ****************** nested class Sequencer **************** */ ResolveAggregates::Sequencer::Sequencer( const DiscreteRange &byRange ) : rs(byRange), direction(byRange.direction) { } universal_integer ResolveAggregates::Sequencer::getNext(void) { universal_integer ret = 0; switch (this->direction) { case DiscreteRange::DIRECTION_UP: ret = this->rs.getLowerBound(); break; case DiscreteRange::DIRECTION_DOWN: ret = this->rs.getUpperBound(); break; } bool b = this->rs.minus(ret, ret); assert(b); return ret; } RangeSet * ResolveAggregates::Sequencer::getRemainder(void) const { return new RangeSet(this->rs); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/ResolveSymbols.cpp0000664000175000017500000001311211243267341022015 0ustar potyrapotyra/* $Id: ResolveSymbols.cpp 4547 2009-08-20 15:42:25Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/ResolveSymbols.hpp" #include #include #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/ConcurrentStat.hpp" #include "frontend/ast/RecordTypeElement.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/reporting/UndefinedSymbol.hpp" #include "frontend/visitor/LookupTypes.hpp" #include "frontend/misc/NameLookup.hpp" namespace ast { void ResolveSymbols::visit(SimpleName &node) { assert(node.name); node.candidates = this->symTab.lookup(*node.name); this->prefixCands = &node.candidates; } void ResolveSymbols::visit(TemporaryName &node) { // only traverse to prefix. node.prefix->accept(*this); } void ResolveSymbols::visit(SelectedName &node) { node.prefix->accept(*this); if (this->prefixCands == NULL) { // error reported somewhere else already return; } std::set symSet = std::set(); for (symListT::iterator i = this->prefixCands->begin(); i != this->prefixCands->end(); /* nothing */) { LookupTypes lt = LookupTypes(true, false); (*i)->declaration.accept(lt); if (lt.declaration == NULL) { i = this->prefixCands->erase(i); continue; } if (lt.declaration->region == NULL) { i = this->prefixCands->erase(i); continue; } symListT c = lt.declaration->region->lookupLocal(*node.name); if (c.empty()) { i = this->prefixCands->erase(i); } // candidate found symSet.insert(c.begin(), c.end()); i++; } if (symSet.empty()) { UndefinedSymbol *us = new UndefinedSymbol(*node.name, node.location); ErrorRegistry::addError(us); this->prefixCands = NULL; return; } node.candidates.insert(node.candidates.begin(), symSet.begin(), symSet.end()); this->prefixCands = &node.candidates; } void ResolveSymbols::visit(AttributeName &node) { assert(false); // attributes not supported yet } void ResolveSymbols::visit(Slice &node) { node.source->accept(*this); symListT *backup = this->prefixCands; this->prefixCands = NULL; node.range->accept(*this); this->prefixCands = backup; } void ResolveSymbols::visit(Subscript &node) { node.source->accept(*this); if (this->prefixCands == NULL) { // error reported already return; } symListT *backup = this->prefixCands; this->prefixCands = NULL; // traverse to indices assert(node.indices != NULL); this->listTraverse(*node.indices); // FIXME mem leak this->prefixCands = new symListT(); *this->prefixCands = NameLookup::shiftSubscriptCands( *backup, node.location); if (this->prefixCands->empty()) { // error reported already via NameLookup delete this->prefixCands; this->prefixCands = NULL; } } void ResolveSymbols::visit(FunctionCall &node) { this->prefixCands = NULL; node.subprog->accept(*this); // leave prefixCands as is, AssociationElement will need them to // shift the lookup scope. if (node.arguments != NULL) { this->listTraverse(*node.arguments); } // leave prefixCands as is, LookupTypes will deal with function symbols // as intended. } void ResolveSymbols::visit(AssociationElement &node) { symListT *backup = this->prefixCands; this->prefixCands = NULL; if (node.formal != NULL) { //FIXME not quite correct, but will work atm. // 1) no idea, where the formal part is, parsing might // have been wrong (but that should be fixed in the parser) // 2) formal names should be looked up only in local scope assert(backup->size() == 1); Symbol *sym = backup->front(); assert(sym->region != NULL); this->symTab.pushRegion(*sym->region); node.formal->accept(*this); this->symTab.popRegion(); } assert(node.actual != NULL); node.actual->accept(*this); this->prefixCands = backup; } void ResolveSymbols::visit(ElementAssociation &node) { /* FIXME for named (record) associations, the scope must be shifted to element names */ if (node.choices != NULL) { this->listTraverse(*node.choices); } if (node.actual != NULL) { node.actual->accept(*this); } } void ResolveSymbols::process(Expression &node) { // cannot be part of a name. get rid of prefixCands this->prefixCands = NULL; } void ResolveSymbols::visit(CompInstStat &node) { this->prefixCands = NULL; assert(node.entityName != NULL); // must have been resolved already by the parser! if (node.entityName->candidates.size() != 1) { // symbol error already reported from parser, bail // out early return; } // set prefixCands to instantiated Entity. this->prefixCands = &node.entityName->candidates; if (node.genericMap != NULL) { this->listTraverse(*node.genericMap); } if (node.portMap != NULL) { this->listTraverse(*node.portMap); } this->prefixCands = NULL; } void ResolveSymbols::process(AstNode &node) { // should not happen, ResolveSymbols is only meant to resolve // formal parts, so make sure we encounter no unhandled node. assert(false); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/GCLoops.cpp0000664000175000017500000000531011173331724020333 0ustar potyrapotyra/* $Id: GCLoops.cpp 4490 2009-04-21 11:53:56Z potyra $ * * Generate intermediate code, loop specific parts. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/GCLoops.hpp" #include "intermediate/opcodes/Jmp.hpp" #include "intermediate/opcodes/Jbe.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/operands/RegisterFactory.hpp" #include "intermediate/container/LabelFactory.hpp" namespace ast { using namespace intermediate; /* * ===================== WHILE ITERATE ======================== */ WhileIterate::WhileIterate( CodeContainer &container ) : cc(container), loopInc(LabelFactory::getLabel("while_iter_inc")), loopDone(LabelFactory::getLabel("while_iter_done")), loopCheck(LabelFactory::getLabel("while_iter_check")) { } WhileIterate::~WhileIterate() { } void WhileIterate::addIteration(void) { this->genIterateCode(); } void WhileIterate::genIterateCode(void) { this->initializeCounter(); this->cc.addCode(loopCheck); this->checkCondition(); this->loopBody(); this->cc.addCode(loopInc); this->incCounter(); Jmp *jmp = new Jmp(this->loopCheck); this->cc.addCode(jmp); this->cc.addCode(loopDone); } /* * ===================== FOR LOOP ITERATE ===================== */ void ForLoopIterate::initializeCounter(void) { Mov *mov = new Mov(&this->init, &this->cnt); this->cc.addCode(mov); } void ForLoopIterate::checkCondition(void) { // FIXME this won't work if rbound is equal to one of the bounds // of the underlying integer type (endless loop). // // The following construct would be one possible solution: // // counter = init; // if (init > bound) goto out; // while (true) { // loopBody(); // if init == bound goto out; // loopInc(); // } // out: Node *goOut; if (this->isAsc) { goOut = new Jb(&this->rbound, &this->cnt, this->loopDone); } else { goOut = new Jb(&this->cnt, &this->rbound, this->loopDone); } this->cc.addCode(goOut); } void ForLoopIterate::incCounter(void) { Register *tmp = this->cc.createRegister(OP_TYPE_INTEGER); Node *inc; if (this->isAsc) { inc = new Add(&this->cnt, ImmediateOperand::getOne(), tmp); } else { inc = new Sub(&this->cnt, ImmediateOperand::getOne(), tmp); } Mov *mov = new Mov(tmp, &this->cnt); this->cc.addCode(inc); this->cc.addCode(mov); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/SetPathName.hpp0000664000175000017500000000471311137610234021205 0ustar potyrapotyra/* $Id: SetPathName.hpp 4323 2009-01-27 13:48:12Z potyra $ * * For different symbol bearing nodes, determine the full vhdl path name. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SET_PATHNAME_HPP_INCLUDED #define __SET_PATHNAME_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" #include namespace ast { //! set the path name of any symbol. /** This visitor will set the corresponding path name of any symbol. * Dependencies: Any visitor that adds declarations *must* have been * executed before. NormalizeAssocs is one example. */ class SetPathName : public TopDownVisitor { public: //! c'tor SetPathName(); /** Visit a Library. * @param node Library node that get's visited. */ virtual void visit(Library &node); /** Visit an Entity declaration. * @param node Entity Declaration node that get's visited. */ virtual void visit(Entity &node); /** Visit an Architecture node. * @param node Architecture node that get's visited. */ virtual void visit(Architecture &node); /** Visit a Package node. * @param node Package node that get's visited. */ virtual void visit(Package &node); /** Visit a Process node. * @param node Process node that get's visited. */ virtual void visit(Process &node); /** Visit a FunctionDeclaration node. * @param node FunctionDeclaration node that get's visited. */ virtual void visit(FunctionDeclaration &node); /** Visit a ProcedureDeclaration node. * @param node ProcedureDeclaration node that get's visited. */ virtual void visit(ProcedureDeclaration &node); private: /** process a generic SymbolDeclaration * @param node SymbolDeclaration to process */ virtual void process(SymbolDeclaration &node); //! Process a generic Callable. /** This function will set the path name of a callable, adding * suffix to it if not NULL. */ void processCallable(Callable &node, const std::string *pSuffix); //! determine the current path name. std::string getPath(void) const; //! stack with entries of the current path. std::list currentPath; //! counter to make unique path names for anonymous constructs. int anonCounter; }; }; /* namespace ast */ #endif /* __SET_PATHNAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/ResolveTypes.hpp0000664000175000017500000004231711307472466021516 0ustar potyrapotyra/* $Id: ResolveTypes.hpp 4882 2009-12-08 15:48:06Z potyra $ * ResolveTypes: perform type analysis. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RESOLVE_TYPES_HPP_INCLUDED #define __RESOLVE_TYPES_HPP_INCLUDED #include #include #include "frontend/visitor/TopDownVisitor.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/LibUnit.hpp" #include "frontend/ast/ConcurrentStat.hpp" #include "frontend/ast/RecordTypeElement.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/misc/SymbolTable.hpp" #include "frontend/ast/NodeFactory.hpp" namespace ast { //! Resolve all types. /** This visitor will resolve all types from the set of candidates * evaluated by the SymbolTable. * * Notes: * * implicit conversions: * universal_integer -> any integer type. * universal_real -> any floating point type. * array definition: index_constraint -> "integer", in case both bounds * are universal_integer and literals or attributes. * * function calls: parameter must match subtype! */ class ResolveTypes : public TopDownVisitor { public: //! c'tor /** @param symTab symbol table instance. */ ResolveTypes(SymbolTable &symTab) : symbolTable(symTab) {} private: /** Visit a CompInstStat * @param node CompInstStat node that gets visited. */ virtual void visit(CompInstStat &node); /** Visit an AssociationElement * @param node AssociationElement node that gets visited. */ virtual void visit(AssociationElement &node); /** Visit an UnconstrainedArrayType * @param node UnconstrainedArrayType node that gets visited. */ virtual void visit(UnconstrainedArrayType &node); /** Visit a DiscreteRange * @param node DiscreteRange node that gets visited. */ virtual void visit(DiscreteRange &node); /** Visit a VarAssignStat * @param node VarAssignStat node that gets visited. */ virtual void visit(VarAssignStat &node); /** Visit a SigAssignStat * @param node SigAssignStat node that gets visited. */ virtual void visit(SigAssignStat &node); /** Visit a Subscript node. * @param node Subscript node that gets visited. */ virtual void visit(Subscript &node); /** Visit a SimpleName node. * @param node SimpleName node that gets visited. */ virtual void visit(SimpleName &node); /** Visit a SelectedName node. * @param node SelectedName node that gets visited. */ virtual void visit(SelectedName &node); /** Visit an AttributeName node. * @param node AttributeName node that gets visited. */ virtual void visit(AttributeName &node); /** Visit a FunctionCall node. * @param node FunctionCall node that gets visited. */ virtual void visit(FunctionCall &node); /** Visit a ConstInteger node. * @param node ConstInteger node that gets visited. */ virtual void visit(ConstInteger &node); /** Visit a ConstReal node. * @param node ConstReal node that gets visited. */ virtual void visit(ConstReal &node); /** Visit an Aggregate node. * @param node Aggregate node that gets visited. */ virtual void visit(Aggregate &node); /** Visit an ElementAssociation node. * @param node ElementAssociation node that gets visited. */ virtual void visit(ElementAssociation &node); /** Visit an Others node. * @param node Others node that gets visited. */ virtual void visit(Others &node); /** Visit a Slice node. * @param node Slice node that gets visited. */ virtual void visit(Slice &node); /** Visit a TemporaryName node. * @param node TemporaryName node that gets visited. */ virtual void visit(TemporaryName &node); /** visit a ReturnStat * @param node node that get's visited. */ virtual void visit(ReturnStat &node); /** visit a RangeConstraintType * @param node node that get's visited. */ virtual void visit(RangeConstraintType &node); /** visit a PhysicalType * @param node node that get's visited. */ virtual void visit(PhysicalType &node); /** visit a RecordType * @param node node that get's visited. */ virtual void visit(RecordType &node); /** visit a FunctionDeclaration * @param node node that get's visited. */ virtual void visit(FunctionDeclaration &node); /** visit a ProcCallStat * @param node node that get's visited. */ virtual void visit(ProcCallStat &node); /** visit a SubtypeIndication * @param node node that get's visited. */ virtual void visit(SubtypeIndication &node); /** Visit a ForLoopStat * @param node ForLoopStat node that get's visited. */ virtual void visit(ForLoopStat &node); /** Visit a WhileLoopStat * @param node WhileLoopStat node that get's visited. */ virtual void visit(WhileLoopStat &node); /** Visit an AssertStat * @param node AssertStat node that get's visited. */ virtual void visit(AssertStat &node); /** Visit a CaseStat * @param node CaseStat node that get's visited. */ virtual void visit(CaseStat &node); /** Visit a WaitStat * @param node WaitStat node that get's visited. */ virtual void visit(WaitStat &node); /** Visit a Process node. * @param node Process node that get's visited. */ virtual void visit(Process& node); /** Visit a WaveFormElem * @param node WaveFormElem node that get's visited. */ virtual void visit(WaveFormElem &node); /** Visit an AttributeSpecification node. * @param node AttributeSpecification node that gets visited. */ virtual void visit(AttributeSpecification &node); public: /** do both TypeDeclarations have the same base type? * @param t1 first TypeDeclaration to check. * @param t2 second TypeDeclaration to check. * @return true, if t1 and t2 have the same base type, * false otherwise. */ static bool baseTypeEqual( const TypeDeclaration &t1, const TypeDeclaration &t2); /** find the base type of t and return it. * @param t type, for which the base type should get looked up. * @return base type of t (or t, if it's no subtype). NULL on error. */ static const TypeDeclaration* findBaseType(const TypeDeclaration *t); /** pick up all index constraints from constrainedArray and store it * in indexConstraints. * @param constrainedArray type referring to a constrained array. * @param indexConstraint list to which indexConstraints should * get added. * @return base type definition of the array. */ static const UnconstrainedArrayType* pickupIndexConstraint( const TypeDeclaration *constrainedArray, std::list &indexConstraint ); /** find out, if type is a constraint array. * @param type type to check * @return true, if it is a constraint array, false otherwise. */ static bool isConstraintArray(const TypeDeclaration *type); private: using TopDownVisitor::process; /** process a subtype indiction that is denoted as resolved. * @param type SubtypeIndication marked as resolved. * @param resolver name of the resolution function. */ void processResolutionFunction( SubtypeIndication &type, SimpleName &resolver); /** process a CaseAlternative node. * @param node CaseAlternative node to process */ void processAlternative(CaseAlternative &node); /** process a generic ValDeclaration node. * @param node node to process */ virtual void process(ValDeclaration &node); /** process a generic LibUnit node. * @param node node to process. */ virtual void process(LibUnit &node); /** process a generic ConditionedStat node. * @param node node to process. */ virtual void process(ConditionedStat &node); /** process a generic SeqStat node. * @param node node to process. */ virtual void process(SeqStat &node); /** process array aggregates * @param node Array Aggregate to process */ void processArrayAgg(Aggregate &node); /** process an ElementAssociation that's part of an Array * Aggregate. */ void processArrayAssoc(ElementAssociation &node); /** process a DiscreteRange that is defined by a * range attribute name. * @param node DiscreteRange node. */ void processDRByName(DiscreteRange &node); /** process a range attribute name * @param node range attribute name node. */ void processRangeAttr(AttributeName &node); /** process a left attribute name * @param node left attribute name node. */ void processLeftAttr(AttributeName &node); /** process a right attribute name * @param node right attribute name node. */ void processRightAttr(AttributeName &node); /** process an event attribute name. * @param node event attribute name node. */ void processEventAttr(AttributeName &node); /** determine the TypeDeclaration resulting when stripping the first * nIdx off. * @param array TypeDeclaration referring to an array type. * @param nIdx number of indices to strip off (flat model: * a multidimensional index counts with the number of * indices. This way it's possible to subscribe to * a single array dimension of a multidimensional array * (which results in an anonymous type). * @param loc Location to use in case an anonymous type should * get created. */ static const TypeDeclaration * subscribedType( const TypeDeclaration &array, unsigned int nIdx, Location loc ); /** process either a physical type or a range constraint type. * @param node node to process */ template void processConstraintType(T &node); /** process a ConstInteger or ConstReal (if it's not physical type.). * In case there are no candidates, put directMatch on the stack. * If candidates are there, check if there are compatible types to * directMatch and return these. * If there aren't filter on possible types that are built from * implicit conversations based on icCompatible. * * @param node ConstInteger or ConstReal node. * @param directMatch native type of the node. * @param icCompatible base type, to which fallback implicit * conversions can be done. */ void processUniversal( Expression &node, const TypeDeclaration *directMatch, enum BaseType icCompatible); /** process a generic Subprogram call. * @param node ProcedureCall statement or FunctionCall statement. * @param mustSingle must the result be unambiguous? */ template void processSubprogCall(T &node, bool mustSingle); /** private type definition of the type declaration list */ typedef std::set typeSetT; /** report an error, if the type is either ambiguous or no * type candidates are left. * @param node errorenous node * @return true if exactly one type is in TypeCandidates. */ bool needUniqueType(AstNode &node) const; /** report an error, if the type is either ambiuous or no * type candidates are left. * Also set the single type candidate as the type of the * Expression. * @param node Expression to which the type should get applied. */ bool needUniqueType(Expression &node) const; /** FIXME interface ... * report an error, if no type candidates are there. * @param loc location of the error. */ void needNotEmpty(Location loc); /** transform the base type of a range, register an error if * given type is not transformable. * @param rangeType the range inherits. * @param loc Location of the Range * @return the resolved base type. */ static enum BaseType transformBaseType(enum BaseType rangeType, Location loc); /** print all types on stderr for debugging purposes * @param types set of types to print. */ static void debugPrintTypes(const typeSetT &types); public: /** determine the first index range for a type an array aggregate * which has the tpye at and the associations assocs. * @param at array type. * @param assocs list of association elements. */ static DiscreteRange * determineIndexRangeAgg( const UnconstrainedArrayType *at, const std::list &assocs); private: /** determine the range constraint of the range type. * @param rangeType range type in question. */ static DiscreteRange * findRange(const TypeDeclaration *rangeType); /** possible types. * When entering a node from its parent node: * - an empty list means to return all possible types * - a list with one element means that this is the wanted type * and that types should get nailed down on this very type. * - a list with several elements means that these are the possible * types and that this list should get reduced by possible types * of this node. */ typeSetT typeCandidates; /** symbol table instance. */ SymbolTable &symbolTable; /** nested class to perform type filtering. * The TypeFilter can be used to reduce a set of symbol candidates to * the ones matching any given wanted types. * * If the wanted types set is empty, it can also fill it with all * possible types that the candidate symbols can provide. */ template class TypeFilter { private: /** reference to list of candidate symbols. */ T &candidates; /** reference list with wanted types */ typeSetT &wantedTypes; public: /** c'tor * @param cands list of candidate types. * @param wantTypes list of wanted types. */ TypeFilter( T &cands, typeSetT &wantTypes ); /** virtual d'tor */ virtual ~TypeFilter() {} /** apply type filtering. */ void apply(void); private: /** operation to map a candidate to a type. * @param element candidate symbol * @return associated type or NULL if no type could get * determined. */ virtual const TypeDeclaration* operator()(typename T::value_type element) const = 0; /** check if given type is compatible to one of * possibleTypes * @param t type to check. * @return true, if the type is compatible. */ bool checkType(const TypeDeclaration *t) const; }; /** class for filtering on list of Symbols. Default implementation does * a type lookup via LookupTypes of a symbol. */ class SymbolFilter : public TypeFilter< std::list > { public: /** c'tor * @param cands list of candidate types. * @param wantTypes list of wanted types. */ SymbolFilter( std::list &cands, typeSetT &wantTypes ) : TypeFilter< std::list >(cands, wantTypes) {} /** operation to map a candidate to a type. * @param element candidate symbol * @return associated type or NULL if no type could get * determined. */ virtual const TypeDeclaration* operator()(Symbol *element) const; }; /** symbol filter which projects the n-ths argument of an * association list to a type. */ class ProjectPositionalArg : public SymbolFilter { public: /** c'tor * @param cands candidate symbols. * @param wantTypes wanted types for the n'ths argument * @param n position of the argument. */ ProjectPositionalArg( std::list &cands, typeSetT &wantTypes, unsigned int n ) : SymbolFilter(cands, wantTypes), position(n) {} /** position of the argument. */ unsigned int position; private: /** operation to map a candidate to a type. * @param element candidate symbol * @return associated type or NULL if no type could get * determined. */ virtual const TypeDeclaration* operator()(Symbol *element) const; }; //! compare the subscripted type to wanted type /** subscribe to wantTypes and compare the result with * candidates, filtering all non-matching types. */ class SubscriptFilter : public TypeFilter< typeSetT > { public: /** c'tor * @param cands type candidates, that will get subscribed. * @param wantTypes wanted types */ SubscriptFilter( typeSetT &cands, typeSetT &wantTypes ) : TypeFilter< typeSetT >(cands, wantTypes) {} protected: /** resolve the type of the source to a subscribed * type. * @param element source type * @return subscribed type. */ virtual const TypeDeclaration* operator()(typeSetT::value_type element) const; }; /* nested class SubscriptFilter */ //! transform/filter cands into an index type. /** take the first SubtypeIndication of indexTypes and check * against it. */ class IndexTypeFilter : public TypeFilter< typeSetT > { public: /** c'tor * @param cands type candidates, for which the index will * get looked up. * @param wantTypes wanted types (will get filled or reduced * @param idx number of the index to filter (1=1st). */ IndexTypeFilter( typeSetT &cands, typeSetT &wantTypes, unsigned int idx ) : TypeFilter< typeSetT >(cands, wantTypes), nIdx(idx) {} private: /** resolve the type of the source to an index type of * an array. * @param element source type * @return index type or NULL if not applicable. */ virtual const TypeDeclaration* operator()(typeSetT::value_type element) const; /** number of the index to filter */ unsigned int nIdx; }; // needs the ability to preload typeCandidates. friend class NodeFactory::TypeDeclHelper; }; }; /* namespace ast */ #endif /* __RESOLVE_TYPES_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GenCode.hpp0000664000175000017500000006001511207763557020354 0ustar potyrapotyra/* $Id: GenCode.hpp 4520 2009-05-29 13:47:27Z potyra $ * * Code generator, which transforms the abstract syntax tree into intermediate * code. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GEN_CODE_HPP_INCLUDED #define __GEN_CODE_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" #include "intermediate/container/CodeContainer.hpp" #include "intermediate/operands/Register.hpp" #include "intermediate/container/Data.hpp" #include "intermediate/opcodes/OpCode.hpp" #include "frontend/visitor/NullVisitor.hpp" #include "frontend/visitor/GCArrays.hpp" #include "frontend/visitor/GCLoops.hpp" #include "frontend/visitor/GCRegisterSet.hpp" #include "frontend/ast/Types.hpp" #include "frontend/misc/Driver.hpp" namespace ast { //! generate intermediate code from the AST /** This visitor will generate intermediate code from the abstract syntax * tree. * Steps, that must have been done prior to running this visitor are: * - all symbols must have been resolved (ParserDriver, Parser in * conjunction with ResolveSymbols) * - types must have been resolved (ResolveTypes) * - intermediate code names must have been set (SetPathNames) * - process drivers and formal parts must have been collected * (GatherImplicits). * - concurrent statements must have been transformed into processes * (not implemented yet) * - CheckLoops * - port map's must have been normalized * - what else? * */ class GenCode : public TopDownVisitor { public: //! c'tor GenCode(); //! alternate c'tor for expression handling /** This c'tor can be used to handle (sub-)expressions. * @param cc CodeContainer instance to reuse. */ GenCode(intermediate::CodeContainer *cc); private: /** Visit a Package node. * @param node Package node that gets visited. */ virtual void visit(Package &node); /** Visit an Entity declaration. * @param node Entity Declaration node that gets visited. */ virtual void visit(Entity &node); /** Visit an Architecture node. * @param node Architecture node that gets visited. */ virtual void visit(Architecture &node); /** Visit a CompInstStat node. * @param node CompInstStat node that gets visited. */ virtual void visit(CompInstStat &node); /** Visit a VarAssignStat * @param node VarAssignStat node that gets visited. */ virtual void visit(VarAssignStat &node); /** Visit a SigAssignStat * @param node SigAssignStat node that gets visited. */ virtual void visit(SigAssignStat &node); /** visit a ConstInteger * @param node node that gets visited. */ virtual void visit(ConstInteger &node); /** visit a ConstReal * @param node node that gets visited. */ virtual void visit(ConstReal &node); /** visit a SimpleName * @param node node that gets visited. */ virtual void visit(SimpleName &node); /** visit an AttributeName * @param node node that gets visited. */ virtual void visit(AttributeName &node); /** visit an IfStat * @param node node that gets visited. */ virtual void visit(IfStat &node); /** visit a Subscript * @param node node that gets visited. */ virtual void visit(Subscript &node); /** visit a Slice * @param node node that gets visited. */ virtual void visit(Slice &node); /** visit a DiscreteRange * @param node node that gets visited. */ virtual void visit(DiscreteRange &node); /** visit a SelectedName * @param node node that gets visited. */ virtual void visit(SelectedName &node); /** visit a FunctionCall * @param node node that gets visited. */ virtual void visit(FunctionCall &node); /** visit an Aggregate * @param node node that gets visited. */ virtual void visit(Aggregate &node); /** visit a ReturnStat * @param node node that gets visited. */ virtual void visit(ReturnStat &node); /** Visit an Signal declaration. * @param node SignalDeclaration node that gets visited. */ virtual void visit(SignalDeclaration &node); /** Visit a VarDeclaration * @param node VarDeclaration node that gets visited. */ virtual void visit(VarDeclaration &node); /** Visit an Constant declaration. * @param node ConstantDeclaration node that gets visited. */ virtual void visit(ConstantDeclaration &node); /** Visit a Process node. * @param node Process node that gets visited. */ virtual void visit(Process &node); /** Visit a ForLoopStat * @param node ForLoopStat node that gets visited. */ virtual void visit(ForLoopStat &node); /** Visit a WhileLoopStat * @param node WhileLoopStat node that gets visited. */ virtual void visit(WhileLoopStat &node); /** Visit a NextStat * @param node NextStat node that gets visited. */ virtual void visit(NextStat &node); /** Visit an ExitStat * @param node ExitStat node that gets visited. */ virtual void visit(ExitStat &node); /** Visit a WaitStat * @param node WaitStat node that gets visited. */ virtual void visit(WaitStat &node); /** Visit an AssertStat * @param node AssertStat node that get's visited. */ virtual void visit(AssertStat &node); /** Visit a ProcCallStat * @param node ReturnStat node that get's visited. */ virtual void visit(ProcCallStat &node); /** visit a ConstArray * @param node node that get's visited. */ virtual void visit(ConstArray &node); /** visit a SubtypeIndication * @param node node that get's visited. */ virtual void visit(SubtypeIndication &node); /** Visit an AttributeSpecification node. * @param node AttributeSpecification node that gets visited. */ virtual void visit(AttributeSpecification &node); /** Visit a CaseStat * @param node CaseStat node that get's visited. */ virtual void visit(CaseStat &node); /** Visit a FunctionDeclaration * @param node FunctionDeclaration node that get's visited. */ virtual void visit(FunctionDeclaration &node); /** Visit a ProcedureDeclaration * @param node ProcedureDeclaration node that get's visited. */ virtual void visit(ProcedureDeclaration &node); /** process (w. direct dispatch) to CaseAlternative * @param node CaseAlternative node. * @param cmpVal compare value of CaseStat node. * @param caseNext label to jump to for the next alternative. * This might be the same as caseOut. * @param caseOut label to jump to after the case statement. */ void processAlternative( CaseAlternative &node, intermediate::Operand *cmpVal, intermediate::Label *caseNext, intermediate::Label *caseOut ); public: //! the code container containing the generated code /** This container will get allocated by the c'tor, but it * won't get free'd again, since the caller will need it. */ intermediate::CodeContainer *container; private: /** process a RangeConstraintType. * @param node RangeConstraintType to generate icode for */ template void processRCT(RangeConstraintType &node); //! Process a generic Callable. /** This function will get called for each Callable (or class * derived from Callable) that gets visited. * * @param node Callable instance. * @return CodeContainer of the create subprogram. */ intermediate::CodeContainer *processCallable(Callable &node); //! Process a generic TypeDeclaration. /** This function will get called for each TypeDeclaration (or class * derived from TypeDeclaration) that gets visited. * * @param node TypeDeclaration instance. */ virtual void process(TypeDeclaration &node); /** process an attribute name "range". * @param node attribute name that is a range attribute. */ void processRangeAttr(AttributeName &node); /** eventually perform an assignment, if the current mode is load. * This is useful, if the storage area must have been determined * before arrays can get assigned. The assignment will hence get * done on the right hand side, in the top expression. * * @param node expression of the assignment. */ void processExpression(Expression &node); /** process a discrete range by from and to members. * @param node DiscreteRange that has from and to set. */ void processDRByBounds(DiscreteRange &node); /** perform an assignment from sourceRegs to destRegs based * on a specified type. * @param type type that the source/destination RegisterSet * refers to. */ void doAssignment(TypeDeclaration &type); /** process an array aggregate association. * @param node ElementAssociation to process. * @param aType type of the aggregate. */ void processArrayAssoc( ElementAssociation &node, TypeDeclaration *aType ); /** process an array aggregate. * @param node Aggregate to process. */ void processArrayAggregate(Aggregate &node); /** process an aggregate, which is of base type record. * @param node Aggregate to process. */ void processRecordAggregate(Aggregate &node); /** process a signal/constant/vardeclaration * @param node declaration to process * @param st desired storage type for intermediate code. * @return resulting Data declaration that is already added * to the current code container. */ intermediate::Data * processValDecl( ValDeclaration &node, enum intermediate::StorageType st ); /** Call a subprogram node. * This function will push the arguments, and call the subprogram. * @param node subprogram to call. * @param foreign foreign annotation to pass on, NULL for non-foreign * @return return register (pointer to value) or NULL for procedures */ template intermediate::Register *callSubprog(T &node, const char *foreign); /** add code to move the return value into a register. * Must only be called at a place where a corresponding transfer * frame is accessible (here only from callSubprog) * * @param node Subprogram in question. * @param callee Reference of the Subprogram. * @return Register with the return value. */ template intermediate::Register * getReturnValue(T &node, intermediate::Reference *callee); typedef std::pair copyBackT; typedef std::list copyBackListT; //! push the argument list of FunctionCall/ProcedureCall node. /** @param node subprogram call, which's argument list should get * transferred. * @param foreign foreign annotation to pass to arguments * NULL for non-foreign. * @return list of intermediate code commands to copy back * actuals to formals after the call. */ template std::list setArgList(T &node, const char *foreign); //! push an argument of a function call on the stack. /** @param c Callable in question. * @param vd corresponding declaration of the formal. * @param arg argument * @param foreign desired foreign annotation or NULL if not foreign * @return intermediate opcode to copy back the actual to the * formal (or NULL if not applicable). */ intermediate::OpCode * setArg( Callable &c, const ValDeclaration &vd, AssociationElement &element, const char *foreign); /** set an argument by value. * used for * - constant (non-composite) * - variable (non-composite) * * @param callee Reference name of the Callee * @param vd formal declaration (may be NULL, if the element * contains a formal) * @param element AssociationElement with the actual. * @param foreign char value to annotate as foreign value, NULL * if not foreign. * @param copyBack prepare target operand for copy back values? * @return copy back command to copy back the actual to the formal * if copyBack is true, NULL otherwise. */ intermediate::OpCode * setArgByValue( intermediate::Reference *callee, const ValDeclaration *vd, AssociationElement &element, const char *foreign, bool copyBack); /* set an argument by passing a pointer * used for * - signal (in, inout) (composite) (here it's a pointer to the signal * pointer) * - variable (composite) * * @param callee Reference name of the Callee * @param vd formal declaration (may be NULL, if the element * contains a formal) * @param element AssociationElement with the actual. * @param foreign char value to annotate as foreign value, NULL * if not foreign. */ void setArgByBasePointer( intermediate::Reference *callee, const ValDeclaration *vd, AssociationElement &element, const char *foreign); /** set an argumenty by passing a pointer to the signal * used fo * - signal (non-composite) * @param callee Reference name of the Callee * @param vd formal declaration (may be NULL, if the element * contains a formal) * @param element AssociationElement with the actual. * @param foreign char value to annotate as foreign value, NULL * if not foreign. */ void setArgByPointer( intermediate::Reference *callee, const ValDeclaration *vd, AssociationElement &element, const char *foreign); /* set an argument by passing a pointer to a temporary. * used for * - composite constant */ void setArgByBasePointerToTemporary( intermediate::Reference *callee, const ValDeclaration &vd, AssociationElement &element, const char *foreign); /** set an argument by passing the base pointer to the driver. * (pointer to driver pointer) * used for * - signal (inout, out) (composite [usePointer=true]) * - signal (inout, out) (non-composite [usePointer=false]) * * For a signal parameter of mode inout, the actual part will * be visited twice! */ void setArgByDriver( intermediate::Reference *callee, const std::list &drivers, const ValDeclaration &vd, AssociationElement &element, const char *foreign, bool usePointer); /** set the constraint arguments for an unconstraint array by * the constraints from the given declaration. * @param cRef Reference to the function call * @param icPrefix intermediate code name prefix. * @param t type containing the constraint. * @param foreign optional foreign annotation. */ void setConstraintsByType( intermediate::Reference *cRef, const std::string &icPrefix, const TypeDeclaration *t, const char *foreign); /** set the constraint arguments for an unconstraint array by * the constraints from the source register set. * @param cRef Reference to the function call * @param icPrefix intermediate code name prefix * @param foreign optional foreign annotation */ void setConstraintsByRS( intermediate::Reference *cRef, const std::string &icPrefix, const char *foreign); /** add data elements for unconstraint array bounds to * the container. * @param node unconstraint ValDeclaration */ void addUnconstraintParams(const ValDeclaration &node); /** pickup the constraints for an unconstraint SimpleName */ void getConstraints(const ValDeclaration &vd); /** copy the array node to the destination register set. * @param node array to copy. */ void processArrayCopy(ConstArray &node); /** udpate (sig-assign) the const array to the destination register * set. * @param node source array. */ void processArrayUpdate(ConstArray &node); //! process a ConstReal or ConstInteger node. /** @param node node to process. */ template void processConst(T &node); //! process a Subscript node with one index. /** @param node subscript to process. * @param indices list with index expressions. */ void processSubscription(Subscript &node, std::list &indices); //! process a next/exit statement. /** @param optCond optional condition when the next/exit statement * should be evaluated. * @param target branch target, if the condition is met. */ void processCFLoopStat( Expression *optCond, intermediate::Label *target); //! assign the expression to the destination register set if true. bool assignExpression; //! is the currently evaluated expression a target? /** For a target, instead of the signal pointer, the driver pointer * must get used. Also direct values in valueReg are not allowed. */ bool isTarget; public: //! source register set RegisterSet sourceRegs; private: //! destination register set RegisterSet destRegs; //! data operand passed to AssignVisitor. /** Contains various additional data depending on the assignMode. * (e.g. delay for signal assignments, severity level for log * opcodes etc. See assignMode for details). */ intermediate::Operand *dataOp; /** Correctly copy/assign composite return values of a function * call to the appropriate place and mangle the source * RegisterSet accordingly. */ void handleCompositeReturn(FunctionCall &node); /** create an init function for the architecture and add it to * the current code container. * @param node Architecture for which to create an init function. */ void createInitFunction(const Architecture &node); /** generate code to initialize an Architecture declared as * foreign. * * @param node foreign Architecture * @param foreign corresponding foreign attribute. */ void foreignInit( const Architecture &node, const AttributeSpecification &foreign ); /** instantiate subcomponents in the architectures init function. * @param node Architecture which holds the subcomponents. */ void instantiateComponents(const Architecture &node); /** instantiate one subcomponent given by the CompInstStat * @param node CompInstStat of the sub component instantiation. */ void instantiateComponent(CompInstStat &node); /** generate an AssociationList where formal * and actual both refer to the declaration. * @param dest append generated Associations in dest * @param src list of ValDeclarations (or derived from VDs). * @param lookupRegion declarative Region where the declarations * of src reside. * * mainly useful for foreignInit(Architecture) */ template void makeSelfAssociations( std::list &dest, const T &src, const DeclarativeRegion *lookupRegion ); /** Set all ports as parameters to reference ref. * @param cont Reference of component container * @param portList port list that should get set as parameters. * @param isForeign is this for a foreign entity? */ void setPortList( intermediate::Reference *cont, const std::list &portList, bool isForeign ); /** Set all generics as parameters to reference ref. * @param cont Reference of component container * @param genericMap generic map that should get set as parameters. * @param isForeign is this for a foreign entity? */ void setGenericMap( intermediate::Reference *cont, std::list &genericMap, bool isForeign); /** create an init function for the process and add it to * the current code container. * @param node Process for which an init function should get created */ void createInitFunction(const Process &node); /** register the drivers in the stack segment for the process. * @param node process with drivers. */ void registerDrivers(const Process &node); /** register one driver in the stack segment for the process. * @param drv driver to register. */ void registerDriver(Driver &drv); /** annotate the type size for a type (in case it is known). * @param data data node that should get annotated. * @param type type of the declaration. */ static void annotateDataSize( intermediate::Data &data, const SubtypeIndication *type ); /** generate code for an index expression of a subscription. * @param index Expression to traverse to. * @return operand with the value of the index. */ intermediate::Operand * getSubscriptIndex(Expression *index); /** add annotations about type for foreign calls/generic/port map * aspects. * @param sp SetParam to be annotated. * @param vd ValDeclaration of the formal. */ static void annotateSetParamType( intermediate::SetParam &sp, const ValDeclaration &vd); /** current enclosing process (or NULL). */ Process *currentProcess; /** current enclosing subprogram declaration (or NULL) */ Callable *currentSubprog; /** mapping for loop statements. */ LoopRegistry loopRegistry; /** list of all instantiaded components by an architecture. */ std::list archComponents; /** operation to be performed for assignments */ enum assignOperationE { /** standard operation: copy the parameter */ ASSIGN_OPERATION_COPY, /** log each element in order with LOG. */ ASSIGN_OPERATION_LOG, /** connect the driver in src to the signal in dst */ ASSIGN_OPERATION_CONNECT, /** issue a WakeOn for each signal in src */ ASSIGN_OPERATION_WAKEON }; /** current operation to be used for assignements. * The default mode copy will perform a copy from source to * dest, either via MOV opcodes for non-signals and UPDATE * opcodes for signals, thereby using dataOp as delay operand. * * Log will add a log opcode for each source, using dataOp * as severity level. */ enum assignOperationE assignOperation; //! generate code to assign src to dst class AssignVisitor : public NullVisitor { public: /** @param source operand referring to the source. * @param dest operand referring to the destination. * @param c CodeContainer to which code snippets should * get added. * @param dataOperand additional data passed to the visitor. * See assignMode for details. */ AssignVisitor( RegisterSet *source, RegisterSet *dest, intermediate::CodeContainer &c, intermediate::Operand *dataOperand, enum assignOperationE mode ) : src(source), dst(dest), container(c), dataOp(dataOperand), operation(mode) {} private: virtual void visit(SubtypeIndication &node); virtual void visit(UnconstrainedArrayType &node); virtual void visit(RecordType &node); virtual void visit(RecordTypeElement &node); virtual void visit(RangeConstraintType &node); virtual void visit(PhysicalType &node); virtual void visit(EnumerationType &node); //! generate code to perform the selected operation. /** @param t baseType of sourceRegs. */ void performOperation(enum BaseType t); //! generate code for an assign statement. /** This method will call the fitting operand methods. * @param t base type of the assigned value. */ void makeAssignment(enum BaseType t); //! log a value present in src void logValue(void); //! issue a wakeon on a signal element void wakeon(enum BaseType t); //! connect the driver in src to the signal in dst void connect(void); //! process a SubtypeIndication with an array base type. /** @param node SubtypeIndication of type array. */ void processArraySubtype(SubtypeIndication &node); /** source operand */ RegisterSet *src; /** target operand */ RegisterSet *dst; /** instance of the CodeContainer */ intermediate::CodeContainer &container; //! delay operand intermediate::Operand *dataOp; //! desired operation enum assignOperationE operation; }; //! process a generic expression, and perform assignments. /** For each subclass of an expression, this class should get * instanciated on the stack when processing the AST node. * The c'tor will take care to stack the necessary variables * and the d'tor will perform the assignment. */ class ProcessStackedExpression { public: //! c'tor /** @param gc GenCode instance. * @param node currently processed Expression. */ ProcessStackedExpression(GenCode &gc, Expression &n); //! d'tor ~ProcessStackedExpression(); private: //! GenCode instance GenCode &genCode; //! currently processed expression node Expression &node; //! backup of assignExpression bool stackedAssignExpression; }; }; }; /* namespace ast */ #endif /* __GEN_CODE_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/ResolveTypes.cpp0000664000175000017500000015462311307676632021516 0ustar potyrapotyra/* $Id: ResolveTypes.cpp 4889 2009-12-09 10:36:10Z potyra $ * ResolveTypes: perform type analysis. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/IfStat.hpp" #include "frontend/ast/NullStat.hpp" #include "frontend/ast/ForLoopStat.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/NextStat.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/ExitStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/WaveFormElem.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/AssertStat.hpp" #include "frontend/ast/VarDeclaration.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/CaseStat.hpp" #include "frontend/ast/CaseAlternative.hpp" #include "frontend/ast/Others.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/PackageBody.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/SubprogBody.hpp" #include "frontend/ast/CondalSigAssign.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/TypeConversion.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/reporting/CompileError.hpp" #include "util/MiscUtil.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/AttributeSpecification.hpp" #include "frontend/visitor/LookupTypes.hpp" #include "frontend/visitor/UnconstraintBounds.hpp" #define SLICE_DEBUG 0 #define SELECTION_DEBUG 0 #define FUNCCALLS_DEBUG 0 namespace ast { void ResolveTypes::visit(CompInstStat &node) { if (node.genericMap != NULL) { for (std::list::const_iterator i = node.genericMap->begin(); i != node.genericMap->end(); i++) { //FIXME this may fail for positional association. // (because there, the formal is missing, but // the wanted type is the projected argument's // type) this->typeCandidates.clear(); (*i)->accept(*this); if (! this->needUniqueType(**i)) { return; } // pin down type (*i)->accept(*this); assert(this->typeCandidates.size() == 1); } } if (node.portMap != NULL) { for (std::list::const_iterator i = node.portMap->begin(); i != node.portMap->end(); i++) { //FIXME same as above. this->typeCandidates.clear(); (*i)->accept(*this); bool ret = this->needUniqueType(**i); if (! ret) { // error already reported, skip. continue; } // pin down type (*i)->accept(*this); assert(this->typeCandidates.size() == 1); } } this->typeCandidates.clear(); } void ResolveTypes::visit(AssociationElement &node) { bool mustSingle = (this->typeCandidates.size() == 1); if (node.formal != NULL) { node.formal->accept(*this); } if (node.actual != NULL) { node.actual->accept(*this); } if (mustSingle) { this->needUniqueType(node); } } void ResolveTypes::visit(UnconstrainedArrayType &node) { assert(node.indexTypes != NULL); node.baseType = BASE_TYPE_ARRAY; assert(node.elementType != NULL); node.elementType->accept(*this); } void ResolveTypes::visit(DiscreteRange &node) { if (node.rangeName != NULL) { this->processDRByName(node); return; } assert(node.from != NULL); assert(node.to != NULL); // gather types of from. typeSetT backup = this->typeCandidates; node.from->accept(*this); typeSetT fromT = this->typeCandidates; this->typeCandidates = backup; node.to->accept(*this); //propagate a RangeConstraintType based on the left bound //(usually the index type) with an additional constraint if ((fromT.size() == 1) && (this->typeCandidates.size() == 1)) { const TypeDeclaration *left = *fromT.begin(); const TypeDeclaration *right = *this->typeCandidates.begin(); enum BaseType resolved = (left->baseType && right->baseType); node.baseType = ResolveTypes::transformBaseType(resolved, node.location); if (node.baseType != BASE_TYPE_RANGE_INT) { CompileError *ce = new CompileError(node, "Not a discrete type in discrete range."); ErrorRegistry::addError(ce); } // if backup is empty, we'll need to deliver all possible // types -> keep types from right hand side. if (! backup.empty()) { this->typeCandidates = backup; } // generate range type SubtypeIndication *rangeType = new SubtypeIndication( left, Location("temporary")); rangeType->constraint = &node; node.type = rangeType; return; } else { // can this happen? at what place? std::cerr << "BOOM: The unexpected happened at " << node.location << std::endl; std::cerr << "left:" << std::endl; this->debugPrintTypes(fromT); std::cerr << "right: " << std::endl; this->debugPrintTypes(this->typeCandidates); std::cerr << "wanted: " << std::endl; this->debugPrintTypes(backup); assert(false); } } void ResolveTypes::processDRByName(DiscreteRange &node) { assert(node.rangeName != NULL); bool mustSingle = this->typeCandidates.size() == 1; node.rangeName->accept(*this); if (mustSingle) { this->needUniqueType(node); } } void ResolveTypes::visit(VarAssignStat &node) { assert(node.target); assert(node.source); // traverse to target this->typeCandidates.clear(); node.target->accept(*this); if (! this->needUniqueType(node)) { return; } // pin down type of target node.target->accept(*this); assert(this->typeCandidates.size() == 1); //traverse to source node.source->accept(*this); if (! this->needUniqueType(node)) { return; } } void ResolveTypes::visit(SigAssignStat &node) { assert(node.target); assert(node.waveForm); // traverse to target this->typeCandidates.clear(); node.target->accept(*this); if (! this->needUniqueType(node)) { return; } // pin down type of target node.target->accept(*this); assert(this->typeCandidates.size() == 1); typeSetT backup = this->typeCandidates; //traverse to every element of the waveform. for (std::list::const_iterator i = node.waveForm->begin(); i != node.waveForm->end(); i++) { this->typeCandidates = backup; (*i)->accept(*this); if (! this->needUniqueType(node)) { return; } } } void ResolveTypes::visit(WaveFormElem &node) { assert(node.value != NULL); node.value->accept(*this); if (node.delay != NULL) { typeSetT backup = this->typeCandidates; this->typeCandidates.clear(); const TypeDeclaration *t = this->symbolTable.getStdStandardType("time"); this->typeCandidates.insert(t); node.delay->accept(*this); this->needUniqueType(*node.delay); this->typeCandidates = backup; } } void ResolveTypes::visit(SimpleName &node) { bool mustSingle = (this->typeCandidates.size() == 1); SymbolFilter tf = SymbolFilter(node.candidates, this->typeCandidates); tf.apply(); if (mustSingle) { this->needUniqueType(node); } else { this->needNotEmpty(node.location); } } void ResolveTypes::visit(SelectedName &node) { /** nested class to transform a record element symbol to the * parent record type. */ class SelectionFilter : public SymbolFilter { public: /** c'tor * @param cands candidate symbols * @param wantTypes list of wanted types */ SelectionFilter(std::list &cands, typeSetT &wantTypes ) : SymbolFilter (cands, wantTypes) {} private: /** operation to transform an element to a parent record type. * @param element RecordTypeElement symbol * @return parent RecordType. */ virtual const TypeDeclaration* operator()(Symbol *element) const { assert(element); if (element->type != SYMBOL_ELEMENT) { return NULL; } RecordTypeElement *rel = dynamic_cast( &(element->declaration)); assert(rel); assert(rel->parent); return rel->parent; } }; assert(node.prefix); assert(node.name); #if SELECTION_DEBUG std::cerr << "Selection enter (prefix at " << node.prefix->location << "=" << node.prefix << ")" << std::endl; ResolveTypes::debugPrintTypes(this->typeCandidates); #endif bool mustSingle = (this->typeCandidates.size() == 1); // 1. filter on current types. SymbolFilter tf = SymbolFilter(node.candidates, this->typeCandidates); tf.apply(); #if SELECTION_DEBUG std::cerr << "Selection after SymbolFilter" << std::endl; ResolveTypes::debugPrintTypes(this->typeCandidates); #endif size_t numSyms = node.candidates.size(); typeSetT backup = this->typeCandidates; this->typeCandidates.clear(); // build list of possible record types of prefix SelectionFilter sf = SelectionFilter(node.candidates, this->typeCandidates); sf.apply(); #if SELECTION_DEBUG std::cerr << "prefix candidates (before traversal)" << std::endl; ResolveTypes::debugPrintTypes(this->typeCandidates); #endif // traverse to prefix node.prefix->accept(*this); #if SELECTION_DEBUG std::cerr << "prefix candidates (after traversal)" << std::endl; ResolveTypes::debugPrintTypes(this->typeCandidates); #endif // prefix types were filtered, filter out candidate symbols which // still match. sf.apply(); this->needNotEmpty(node.prefix->location); // restore old candidates this->typeCandidates = backup; if (node.candidates.size() != numSyms) { #if SELECTION_DEBUG std::cerr << "Selection: again" << std::endl; #endif // candidates got reduced by the SelectionFilter. Filter by // wanted types again. tf.apply(); // apply types to prefix backup = this->typeCandidates; this->typeCandidates.clear(); // regenerate the only possible type the prefix may take sf.apply(); // it *must* be one assert(this->typeCandidates.size() == 1); // apply it to the prefix node.prefix->accept(*this); this->typeCandidates = backup; } if (mustSingle) { this->needUniqueType(node); } else { this->needNotEmpty(node.location); } } void ResolveTypes::visit(AttributeName &node) { typedef void (ResolveTypes::*rtANMethT)(AttributeName &); // FIXME isn't that crack? cf. comments in BuiltinSymbolTable std::map attrCals; attrCals["range"] = &ResolveTypes::processRangeAttr; attrCals["left"] = &ResolveTypes::processLeftAttr; attrCals["right"] = &ResolveTypes::processRightAttr; attrCals["event"] = &ResolveTypes::processEventAttr; // TODO // // FIXME actually processEventAttr looks good to be // used as a more general way to resolve attributes. std::map::iterator i = attrCals.find(*node.name); if (i == attrCals.end()) { std::cerr << "cannot find attribute <" << *node.name << ">." << std::endl; assert(false); } (this->*(i->second))(node); } void ResolveTypes::processRangeAttr(AttributeName &node) { assert(node.prefix != NULL); bool mustSingle = this->typeCandidates.size() == 1; typeSetT backup = this->typeCandidates; this->typeCandidates.clear(); node.prefix->accept(*this); IndexTypeFilter itf = IndexTypeFilter(this->typeCandidates, backup, 1); itf.apply(); if (mustSingle) { bool res = this->needUniqueType(node); if (res) { switch ((*backup.begin())->baseType) { case BASE_TYPE_INTEGER: node.baseType = BASE_TYPE_RANGE_INT; break; case BASE_TYPE_REAL: node.baseType = BASE_TYPE_RANGE_REAL; break; default: assert(false); } // pin down type... node.prefix->accept(*this); } } this->typeCandidates = backup; } void ResolveTypes::processEventAttr(AttributeName &node) { assert(node.prefix != NULL); // first traverse to prefix. Type must be clear from the // context. typeSetT backup = this->typeCandidates; this->typeCandidates.clear(); node.prefix->accept(*this); // there may be only one type for the prefix! bool res = this->needUniqueType(node); if (res) { node.prefix->accept(*this); } this->typeCandidates = backup; // filter on symbols SymbolFilter tf = SymbolFilter(node.candidates, this->typeCandidates); tf.apply(); } void ResolveTypes::processLeftAttr(AttributeName &node) { assert(false); } void ResolveTypes::processRightAttr(AttributeName &node) { assert(false); } void ResolveTypes::visit(FunctionCall &node) { assert(node.subprog); assert(node.arguments); bool mustSingle = (this->typeCandidates.size() == 1); SymbolFilter rf = SymbolFilter(node.subprog->candidates, this->typeCandidates); rf.apply(); // minor check that no positional arguments are present after named // arguments (TODO should go somewhere else) // FIXME assert's, that no named areguments are present at all, // since these are currently not supported. bool positional = true; for (std::list::const_iterator i = node.arguments->begin(); i != node.arguments->end(); i++) { if ((*i)->formal) { positional = false; assert(false); //named arguments not yet supported. } else { if (! positional) { CompileError *ce = new CompileError( (*i)->formal->location, "Positional argument after " "named argument"); ErrorRegistry::addError(ce); return; } } } typeSetT backup = this->typeCandidates; this->typeCandidates.clear(); this->processSubprogCall(node, mustSingle); // filter again, to reduce return types. this->typeCandidates = backup; rf.apply(); if (mustSingle && node.subprog->candidates.size() == 1) { node.definition = dynamic_cast( &node.subprog->candidates.front()->declaration ); assert(node.definition != NULL); } if (mustSingle) { this->needUniqueType(node); } } void ResolveTypes::visit(ProcCallStat &node) { assert(node.subprog); assert(node.arguments); this->typeCandidates.clear(); this->processSubprogCall(node, true); if (node.subprog->candidates.size() != 1) { // error reported from AssociationElement list already return; } Symbol *sym = node.subprog->candidates.front(); node.definition = dynamic_cast(&sym->declaration); } void ResolveTypes::visit(SubtypeIndication &node) { this->typeCandidates.clear(); // ignore typeName, that's already handled in c'tor // FIXME that's too easy... constraint must be of a // specific type! if (node.constraint != NULL) { node.constraint->accept(*this); this->typeCandidates.clear(); } if (node.resolutionFunction != NULL) { SimpleName *sn = dynamic_cast(node.resolutionFunction); if (! sn) { // FIXME better error message. Imho this can // only happen for selected names. However // resolution functions should only be expanded names, // which in turn would result in SimpleName. CompileError *ce = new CompileError( *node.resolutionFunction, "There is something wrong"); ErrorRegistry::addError(ce); return; } this->processResolutionFunction(node, *sn); } if (node.indexConstraint == NULL) { return; } /* base must be unconstraint array */ const UnconstrainedArrayType *base = dynamic_cast( this->findBaseType(node.declaration)); assert(base != NULL); assert(base->indexTypes != NULL); if (node.indexConstraint->size() != base->indexTypes->size()) { CompileError *ce = new CompileError(node, "wrong number of indices for index constraint."); ErrorRegistry::addError(ce); return; } std::list::iterator j = base->indexTypes->begin(); for (std::list::iterator i = node.indexConstraint->begin(); i != node.indexConstraint->end(); i++, j++) { this->typeCandidates.insert(*j); (*i)->accept(*this); this->typeCandidates.clear(); } } void ResolveTypes::processResolutionFunction( SubtypeIndication &type, SimpleName &resolver ) { assert(type.resolutionFunction != NULL); // 1. filter by return type. this->typeCandidates.insert(&type); SymbolFilter sf = SymbolFilter(resolver.candidates, this->typeCandidates); sf.apply(); this->typeCandidates.clear(); // 2. filter by parameter type (one dimensional array, element type // must match this type. for (std::list::iterator i = resolver.candidates.begin(); i != resolver.candidates.end(); /* nothing */) { FunctionDeclaration *fd = dynamic_cast( &(*i)->declaration); if (fd == NULL) { i = resolver.candidates.erase(i); continue; } if ((fd->arguments == NULL) || (fd->arguments->size() != 1)) { i = resolver.candidates.erase(i); continue; } const ValDeclaration *arg = fd->arguments->front(); if (! arg->isUnconstraint()) { i = resolver.candidates.erase(i); continue; } if (arg->storageClass != ValDeclaration::OBJ_CLASS_CONSTANT) { i = resolver.candidates.erase(i); continue; } const TypeDeclaration *elementT = ResolveTypes::subscribedType(*arg->subtypeIndic, 1, resolver.location); if (elementT == NULL) { i = resolver.candidates.erase(i); continue; } if (! ResolveTypes::baseTypeEqual(*elementT, type)) { i = resolver.candidates.erase(i); continue; } i++; } if (! resolver.candidates.size() == 1) { CompileError *ce = new CompileError(resolver, "Type Error for resolution function"); ErrorRegistry::addError(ce); } } template void ResolveTypes::processSubprogCall(T &node, bool mustSingle) { assert(node.arguments); assert(node.subprog); /* FIXME this is not quite right yet. * Example: * x : integer; * * if 2 = x then * ... * * Currently, 2 as first operand will resolve = uniquely to * "="(anon, anon: universal_integer); * * Hence it will result in a type error, because x is of a different * type (and as non-universal type not convertible). */ //! filter out symbols by number of arguments. /** FIXME currently this filter relies on no formal parts being * present, because these could indicate individual * association. * For individual association, one approach would be to * flatten every type (which has the caveat, that conversion * functions cannot be handled that way, since these need to * be done on the complete composite type, if no individual * association is used) and check again. * Another possible approach, would be to count the different * formal parts with different names. * This filter also doesn't take into account yet, that * formal parts are a means of reducing the candidates as * well (e.g. if a formal part with given name is not present * for a candidate). */ class ArgcFilter { public: /** c'tor * @param cands candidate symbols of callable's * @param args current argument list */ ArgcFilter(std::list &cands, const std::list &args ) : sc(cands), a(args) {} /** apply the filter */ void apply(void) { for (std::list::iterator i = this->sc.begin(); i != this->sc.end(); /* nothing */) { //FIXME see long comment above Callable *c = dynamic_cast( &(*i)->declaration); if (c == NULL) { i = this->sc.erase(i); continue; } if ( (c->arguments == NULL) && this->a.empty()) { i++; continue; } if (c->arguments == NULL) { // args not empty i = this->sc.erase(i); continue; } if (c->arguments->size() != this->a.size()) { i = this->sc.erase(i); continue; } i++; } } private: //!candidates std::list ≻ //!arguments const std::list &a; }; // filter on number of arguments ArgcFilter argcf = ArgcFilter( node.subprog->candidates, *node.arguments); argcf.apply(); ProjectPositionalArg paf = ProjectPositionalArg( node.subprog->candidates, this->typeCandidates, 0); size_t firstSinglePos = node.arguments->size(); for (std::list::const_iterator i = node.arguments->begin(); i != node.arguments->end(); i++, paf.position++) { //TODO: named arguments. assert((*i)->formal == NULL); assert((*i)->actual); /* FIXME open associations */ this->typeCandidates.clear(); // fetch *all* possible types into typeCandidates. paf.apply(); // if there's only a single type candidate, recall // the position so that we can avoid duplicate traversal // for type pinning if ((this->typeCandidates.size() == 1) && (paf.position < firstSinglePos)) { firstSinglePos = paf.position; } #if FUNCCALLS_DEBUG std::cerr << (*i)->location << ": " << *i << " all possible types " << std::endl; this->debugPrintTypes(this->typeCandidates); #endif /* FUNCCALLS_DEBUG */ // traverse to actual part (*i)->accept(*this); #if FUNCCALLS_DEBUG std::cerr << (*i)->location << ": " << *i << " reduced set" << std::endl; this->debugPrintTypes(this->typeCandidates); #endif /* FUNCCALLS_DEBUG */ // now typeCandidates contains the set of possbile types, that // can be matched by the argument. filter the possible types // again (actually possible types are reduced not by // actual types, but rather by a reduced set of possible types). paf.apply(); } this->typeCandidates.clear(); if (! mustSingle) { return; } // check if unique if (1 < node.subprog->candidates.size()) { std::string msg = "Ambiguous subprogram call of <"; msg += *node.subprog->name + ">. "; #if FUNCCALLS_DEBUG std::cerr << "TYPE ERROR: " << node << std::endl; #endif /* FUNCCALLS_DEBUG */ CompileError *ce = new CompileError(node, msg); ErrorRegistry::addError(ce); return; } if (node.subprog->candidates.empty()) { return; } // now each argument *must* result in a single type! // pin these down. paf.position = 0; for (std::list::const_iterator i = node.arguments->begin(); i != node.arguments->end(); i++, paf.position++) { // break early if other arguments already have been // pinned down. if (paf.position == firstSinglePos) { break; } //TODO: named arguments. assert((*i)->formal == NULL); assert((*i)->actual); /* FIXME open associations */ this->typeCandidates.clear(); // fetch *all* possible types into typeCandidates // (can be only one) paf.apply(); assert(this->typeCandidates.size() == 1); // traverse to actual part to pin it down (*i)->accept(*this); } this->typeCandidates.clear(); } void ResolveTypes::visit(Subscript &node) { // FIXME 6.4 (and 10.5) make it not explicitely clear, if the // index constraints may be used to eliminate possibile // interpretions in the first place. // // Is this valid? // // type foo is range 1 to 10; // type bar is range 1 to 20; // type x is array(foo) of integer; // type y is array(bar) of integer; // // function f() return x; // function f() return y; // // var a : foo; // var b : bar; // var i : integer; // // a := f(a); // a := f(b); // // IMHO the only rule here would be that the prefix must be an array // type, so wether it has the correct number of indices // and wether the index types are set correct shouldn't matter. // // The current implementation eliminates candidates of f via // index types though. assert(node.source != NULL); assert(node.indices != NULL); typeSetT wantTypes = this->typeCandidates; bool mustSingle = wantTypes.size() == 1; this->typeCandidates.clear(); node.source->accept(*this); SubscriptFilter sf = SubscriptFilter(this->typeCandidates, wantTypes); sf.apply(); typeSetT backup = this->typeCandidates; if (! mustSingle) { // fetch index types unsigned int nIdx = 1; for (std::list::iterator i = node.indices->begin(); i != node.indices->end(); i++) { this->typeCandidates.clear(); IndexTypeFilter itf = IndexTypeFilter(backup, this->typeCandidates, nIdx); itf.apply(); (*i)->accept(*this); nIdx++; } } this->typeCandidates = backup; if (mustSingle) { // pin down source node.source->accept(*this); // and pin down index types unsigned int nIdx = 1; for (std::list::iterator i = node.indices->begin(); i != node.indices->end(); i++) { this->typeCandidates.clear(); IndexTypeFilter itf = IndexTypeFilter(backup, this->typeCandidates, nIdx); itf.apply(); (*i)->accept(*this); if (! this->needUniqueType(**i)) { this->typeCandidates = backup; return; } nIdx++; } } this->typeCandidates = wantTypes; if (mustSingle) { bool ret = this->needUniqueType(node); if (! ret) { return; } // check number of indices const TypeDeclaration *d = ResolveTypes::findBaseType(node.source->type); const UnconstrainedArrayType *ua = dynamic_cast(d); assert(ua != NULL); if (node.indices->size() < ua->indexTypes->size()) { CompileError *ce = new CompileError(node, "Too few indices"); ErrorRegistry::addError(ce); } if (node.indices->size() > ua->indexTypes->size()) { CompileError *ce = new CompileError(node, "Too many indices"); ErrorRegistry::addError(ce); } } else { this->needNotEmpty(node.location); } } void ResolveTypes::visit(ConstInteger &node) { if (node.physUnit != NULL) { // unit is a physical type. Let SimpleName handle this. node.physUnit->accept(*this); node.type = node.physUnit->type; return; } const TypeDeclaration *uInt = this->symbolTable.getStdStandardType("__universal_integer__"); assert(uInt); this->processUniversal(node, uInt, BASE_TYPE_INTEGER); } void ResolveTypes::visit(ConstReal &node) { const TypeDeclaration *uReal = this->symbolTable.getStdStandardType("__universal_real__"); assert(uReal); this->processUniversal(node, uReal, BASE_TYPE_REAL); } void ResolveTypes::visit(Aggregate &node) { //FIXME handles only array aggregates atm. assert(node.associations != NULL); bool isArray = false; for (typeSetT::iterator i = this->typeCandidates.begin(); i != this->typeCandidates.end(); /* nothing */) { switch((*i)->baseType) { case BASE_TYPE_ARRAY: isArray = true; i++; continue; case BASE_TYPE_RECORD: isArray = false; i++; continue; default: /* fall through */ break; } // not a composite type, remove. typeSetT::iterator j = i; i++; this->typeCandidates.erase(j); } if (! this->needUniqueType(node)) { return; } // typeCandidates contain exactly one type if (isArray) { this->processArrayAgg(node); node.baseType = BASE_TYPE_ARRAY; return; } node.baseType = BASE_TYPE_RECORD; // TODO record Aggregates return; } void ResolveTypes::processArrayAgg(Aggregate &node) { // must have been filtered by caller. assert(this->typeCandidates.size() == 1); // determine subscripted type const TypeDeclaration *wanted = *(this->typeCandidates.begin()); for (std::list::const_iterator i = node.associations->begin(); i != node.associations->end(); i++) { this->typeCandidates.clear(); this->typeCandidates.insert(wanted); // don't dispatch, call directly instead. this->processArrayAssoc(**i); } // restore candidates this->typeCandidates.clear(); this->typeCandidates.insert(wanted); if (ResolveTypes::isConstraintArray(node.type)) { return; } // unconstraint array as base type. Try to calculate bounds. UnconstraintBounds ub = UnconstraintBounds(); node.accept(ub); assert(ub.bounds != NULL); // generate a new SubtypeIndication with the range constraint. SubtypeIndication *si = new SubtypeIndication(node.type, node.location); si->indexConstraint = new std::list(); si->indexConstraint->push_back(ub.bounds); node.type = si; } void ResolveTypes::visit(ElementAssociation &node) { assert(false); // use direct calls instead of dispatching. } void ResolveTypes::visit(ReturnStat &node) { if (node.result == NULL) { // no return expression, break early. return; } // determine return type // FIXME catch error that result is present, but // node refers to a Procedure LookupTypes lat = LookupTypes(false, false); assert(node.enclosingSubprog != NULL); node.enclosingSubprog->accept(lat); assert(lat.declaration != NULL); this->typeCandidates.clear(); this->typeCandidates.insert(lat.declaration); // traverse to result expression (will report errors, since // there is only a single type in wantTypes) node.result->accept(*this); this->typeCandidates.clear(); } void ResolveTypes::visit(Process &node) { if (node.sensitivityList != NULL) { for (std::list::iterator i = node.sensitivityList->begin(); i != node.sensitivityList->end(); i++) { this->typeCandidates.clear(); (*i)->accept(*this); if (! this->needUniqueType(**i)) { continue; } (*i)->accept(*this); this->needUniqueType(**i); } } if (node.declarations != NULL) { this->listTraverse(*node.declarations); } this->typeCandidates.clear(); if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); } } void ResolveTypes::processArrayAssoc(ElementAssociation &node) { // need exactly one candidate. If that's not true, Aggregate should // have reported an error and not called this method. assert(this->typeCandidates.size() == 1); if (node.choices != NULL) { // determine possible index types. typeSetT backup = this->typeCandidates; this->typeCandidates.clear(); IndexTypeFilter itf = IndexTypeFilter(backup, this->typeCandidates, 1); itf.apply(); typeSetT wantedIndexTypes = this->typeCandidates; for (std::list::const_iterator i = node.choices->begin(); i != node.choices->end(); i++) { this->typeCandidates = wantedIndexTypes; (*i)->accept(*this); // check if index types match. itf.apply(); if (! this->needUniqueType(node)) { // type error, bail out immediately return; } assert((*i)->type != NULL); } this->typeCandidates = backup; } assert(node.actual != NULL); // getting tricky: // * if it's a multidimensional array, remove the first index and // traverse to actual. // * otherwise determine the element type and traverse to actual. // // Examples: (0 => (0 => '1', 1 => '0'), 1 to 3 => (others => '1')) // is valid for // array(0 to 3, 0 to 1) of character; // *and* // at : array(0 to 1) of character; // array(0 to 3) of at; const TypeDeclaration *wanted = *this->typeCandidates.begin(); const TypeDeclaration *needed = ResolveTypes::subscribedType(*wanted, 1, node.location); // traverse to actual this->typeCandidates.clear(); this->typeCandidates.insert(needed); node.actual->accept(*this); this->typeCandidates.clear(); this->typeCandidates.insert(wanted); } const TypeDeclaration * ResolveTypes::subscribedType( const TypeDeclaration &array, unsigned int nIdx, Location loc ) { assert(array.baseType == BASE_TYPE_ARRAY); std::list idxConstraint = std::list(); const UnconstrainedArrayType *uArr = ResolveTypes::pickupIndexConstraint(&array, idxConstraint); assert(uArr->indexTypes != NULL); if (uArr->indexTypes->size() < nIdx) { // FIXME: issue error here. assert(false); } if (uArr->indexTypes->size() == nIdx) { // subscription to base type. return uArr->elementType; } // partial subscription. strip off first nIdx indices. std::list::iterator i = uArr->indexTypes->begin(); for (unsigned int c = nIdx; c > 0; c--) { i++; } std::list *shiftIndices = new std::list(); shiftIndices->insert(shiftIndices->end(), i, uArr->indexTypes->end()); // that's the new anonymous base type. UnconstrainedArrayType *ua = new UnconstrainedArrayType( new std::string("__anonymous__"), shiftIndices, uArr->elementType, loc); if (idxConstraint.empty()) { // must have been an Unconstraint array already. return ua; } // FIXME must be checked somewhere (hello parser?) assert(idxConstraint.size() == uArr->indexTypes->size()); // strip off nIdx indices from indexConstraint as well. for (std::list::iterator j = idxConstraint.begin(); nIdx > 0; nIdx--) { assert(j != idxConstraint.end()); j = idxConstraint.erase(j); } SubtypeIndication *si = new SubtypeIndication(ua, loc); si->indexConstraint = new std::list(idxConstraint); return si; } void ResolveTypes::visit(Others &node) { if (this->typeCandidates.size() == 1) { this->needUniqueType(node); } // otherwise others does not affect type candidates. } void ResolveTypes::visit(Slice &node) { assert(node.source); #if SLICE_DEBUG std::cerr << "Slice before source" << std::endl; ResolveTypes::debugPrintTypes(this->typeCandidates); #endif node.source->accept(*this); #if SLICE_DEBUG std::cerr << "Slice after source" << std::endl; ResolveTypes::debugPrintTypes(this->typeCandidates); #endif typeSetT backup = this->typeCandidates; this->typeCandidates.clear(); // determine index types and store these in typeCandidates IndexTypeFilter itf = IndexTypeFilter(backup, this->typeCandidates, 1); itf.apply(); #if SLICE_DEBUG std::cerr << "#indexTypes for " << *node.source << "=" << this->typeCandidates.size() << std::endl; std::cerr << "#source types=" << backup.size() << std::endl; #endif // traverse to range and filter out types assert(node.range); node.range->accept(*this); itf.apply(); this->typeCandidates = backup; this->needUniqueType(node); } void ResolveTypes::visit(TemporaryName &node) { // only traverse to prefix, do nothing else assert(node.prefix != NULL); node.prefix->accept(*this); // set the type in case it's known if (this->typeCandidates.size() == 1) { this->needUniqueType(node); } } void ResolveTypes::visit(AttributeSpecification &node) { this->typeCandidates.clear(); assert(node.declaration != NULL); assert(node.declaration->type != NULL); this->typeCandidates.insert(node.declaration->type); assert(node.init != NULL); node.init->accept(*this); this->needUniqueType(node); this->typeCandidates.clear(); } void ResolveTypes::processUniversal( Expression &node, const TypeDeclaration *directMatch, enum BaseType icCompatible ) { assert(directMatch != NULL); // no type candidates -> put directMatch (universal_int, U.real) // in there. // (implicit conversions are only allowed, if the wanted type // is known, LRM 7.3.5). if (this->typeCandidates.empty()) { this->typeCandidates.insert(directMatch); this->needUniqueType(node); return; } bool mustSingle = (this->typeCandidates.size() == 1); // check if there is a direct match for __universal_integer__ typeSetT backup = this->typeCandidates; for (typeSetT::iterator i = backup.begin(); i != backup.end(); /* nothing */) { if (! ResolveTypes::baseTypeEqual(**i, *directMatch)) { typeSetT::iterator j = i; i++; backup.erase(j); continue; } i++; } if (! backup.empty()) { // direct match against universal_integer found. return this. this->typeCandidates = backup; this->needUniqueType(node); return; } // node is of type (convertible) universal_integer. Filter out all // types that are not integer based. for (typeSetT::iterator i = this->typeCandidates.begin(); i != this->typeCandidates.end(); /* nothing */) { if ((*i)->baseType != icCompatible) { typeSetT::iterator j = i; i++; this->typeCandidates.erase(j); continue; } i++; } if (mustSingle) { this->needUniqueType(node); } } void ResolveTypes::visit(RangeConstraintType &node) { this->processConstraintType(node); } void ResolveTypes::visit(PhysicalType &node) { this->processConstraintType(node); if (node.baseType != BASE_TYPE_INTEGER) { node.baseType = BASE_TYPE_INTEGER; CompileError *err = new CompileError(node, "Constraint must be an integral type."); ErrorRegistry::addError(err); } } void ResolveTypes::visit(RecordType &node) { // nothing to do, *don't* traverse to elements! } void ResolveTypes::visit(FunctionDeclaration &node) { // do *not* traverse to returnType this->process(node); } void ResolveTypes::visit(ForLoopStat &node) { // set type declaration of loop parameter specification from // discrete range. this->typeCandidates.clear(); assert(node.range != NULL); node.range->accept(*this); bool ret = this->needUniqueType(node); if (! ret) { return; } const TypeDeclaration *t = *this->typeCandidates.begin(); if (t->isUniversal) { t = this->symbolTable.getStdStandardType("integer"); this->typeCandidates.clear(); this->typeCandidates.insert(t); } // actually pin down type node.range->accept(*this); assert(node.loopVariable != NULL); assert(! this->typeCandidates.empty()); t = *this->typeCandidates.begin(); // check if it is a discrete type. switch (t->baseType) { case BASE_TYPE_INTEGER: break; default: { CompileError *ce = new CompileError(*node.range, "For loop parameter must be discrete."); ErrorRegistry::addError(ce); return; } } node.loopVariable->subtypeIndic = new SubtypeIndication(t, node.loopVariable->location); this->typeCandidates.clear(); // handle seqstats via process. this->process(node); } void ResolveTypes::visit(WhileLoopStat &node) { this->typeCandidates.clear(); // condition must be of type boolean const TypeDeclaration *boolean = this->symbolTable.getStdStandardType("boolean"); assert(boolean != NULL); assert(node.condition != NULL); this->typeCandidates.insert(boolean); node.condition->accept(*this); this->typeCandidates.clear(); if (node.loopStats != NULL) { this->listTraverse(*node.loopStats); } } void ResolveTypes::visit(AssertStat &node) { this->typeCandidates.clear(); // condition must be of type boolean const TypeDeclaration *boolean = this->symbolTable.getStdStandardType("boolean"); assert(boolean != NULL); assert(node.condition != NULL); this->typeCandidates.insert(boolean); node.condition->accept(*this); this->typeCandidates.clear(); if (node.report != NULL) { // report must be of type string (i.e. compatible to) const TypeDeclaration *strT = this->symbolTable.getStdStandardType("string"); assert(strT != NULL); this->typeCandidates.insert(strT); node.report->accept(*this); this->typeCandidates.clear(); } if (node.severity != NULL) { // report must be of type SEVERITY_LEVEL const TypeDeclaration *sevLvl = this->symbolTable.getStdStandardType( "severity_level"); assert(sevLvl != NULL); this->typeCandidates.insert(sevLvl); node.severity->accept(*this); this->typeCandidates.clear(); } } void ResolveTypes::visit(WaitStat &node) { this->typeCandidates.clear(); // handle condition this->process(node); if (node.timeout != NULL) { // timeout must be of type "time" const TypeDeclaration *time = this->symbolTable.getStdStandardType("time"); this->typeCandidates.insert(time); node.timeout->accept(*this); this->needUniqueType(*node.timeout); this->typeCandidates.clear(); } if (node.sensitivities == NULL) { return; } // node.sensitivities != NULL for (std::list::iterator i = node.sensitivities->begin(); i != node.sensitivities->end(); i++) { // TODO (probably in a separate step): the sensitivity list // must consist of solely static names. (*i)->accept(*this); if (! this->needUniqueType(**i)) { this->typeCandidates.clear(); continue; } (*i)->accept(*this); this->needUniqueType(**i); this->typeCandidates.clear(); } } void ResolveTypes::processAlternative(CaseAlternative &node) { assert(node.isVals != NULL); assert(node.thenStats != NULL); typeSetT backup = this->typeCandidates; assert(backup.size() == 1); for (std::list::iterator i = node.isVals->begin(); i != node.isVals->end(); i++) { this->typeCandidates = backup; (*i)->accept(*this); this->needUniqueType(**i); } this->typeCandidates.clear(); this->listTraverse(*node.thenStats); this->typeCandidates = backup; } void ResolveTypes::visit(CaseStat &node) { assert(node.select != NULL); assert(node.alternatives != NULL); this->typeCandidates.clear(); node.select->accept(*this); // TODO lrm, 8.8: base type must be discrete, or a one dimensional // array of a character type. bool r = this->needUniqueType(*node.select); if (! r) { // don't even bother alternatives on type error this->typeCandidates.clear(); return; } // pin down type node.select->accept(*this); if (this->typeCandidates.size() != 1) { return; } for (std::list::iterator i = node.alternatives->begin(); i != node.alternatives->end(); i++) { this->processAlternative(**i); } this->typeCandidates.clear(); } template void ResolveTypes::processConstraintType(T &node) { this->typeCandidates.clear(); assert(node.constraint != NULL); if (node.constraint->rangeName != NULL) { // handle these via discrete range. node.constraint->accept(*this); if (! this->needUniqueType(node)) { return; } const TypeDeclaration *t = *this->typeCandidates.begin(); switch(t->baseType) { case BASE_TYPE_RANGE_INT: node.baseType = BASE_TYPE_INTEGER; break; case BASE_TYPE_RANGE_REAL: node.baseType = BASE_TYPE_RANGE_REAL; break; default: { node.baseType = BASE_TYPE_UNSET; CompileError *ce = new CompileError(node.location, "invalid type for constraint."); ErrorRegistry::addError(ce); } } return; } assert(node.constraint->from != NULL); assert(node.constraint->to != NULL); node.constraint->from->accept(*this); if (! this->needUniqueType(*node.constraint->from)) { this->typeCandidates.clear(); node.baseType = BASE_TYPE_UNSET; return; } // traverse again, to pin down from type node.constraint->from->accept(*this); // FIXME can this happen? assert(this->typeCandidates.size() == 1); const TypeDeclaration *t = *this->typeCandidates.begin(); enum BaseType left = t->baseType; this->typeCandidates.clear(); node.constraint->to->accept(*this); if (! this->needUniqueType(*node.constraint->to)) { this->typeCandidates.clear(); node.baseType = BASE_TYPE_UNSET; return; } // traverse again, to pin to from type node.constraint->to->accept(*this); assert(this->typeCandidates.size() == 1); // set base type t = *this->typeCandidates.begin(); this->typeCandidates.clear(); left = left && t->baseType; switch(left) { case BASE_TYPE_INTEGER: case BASE_TYPE_REAL: node.baseType = left; break; default: { node.baseType = BASE_TYPE_UNSET; CompileError *ce = new CompileError(node.location, "invalid type for constraint."); ErrorRegistry::addError(ce); } } } bool ResolveTypes::baseTypeEqual( const TypeDeclaration &t1, const TypeDeclaration &t2 ) { // determine base types. const TypeDeclaration *b1 = ResolveTypes::findBaseType(&t1); const TypeDeclaration *b2 = ResolveTypes::findBaseType(&t2); // compare pointer! return b1 == b2; } const TypeDeclaration* ResolveTypes::findBaseType(const TypeDeclaration* t) { if (t == NULL) { return NULL; } const SubtypeIndication *s = dynamic_cast(t); if (s == NULL) { // not a subtype return t; } // recurse assert(s->declaration); return ResolveTypes::findBaseType(s->declaration); } const UnconstrainedArrayType* ResolveTypes::pickupIndexConstraint( const TypeDeclaration *constrainedArray, std::list &indexConstraint ) { assert(constrainedArray != NULL); assert(constrainedArray->baseType == BASE_TYPE_ARRAY); const SubtypeIndication *sub = dynamic_cast(constrainedArray); if ((sub != NULL) && (sub->indexConstraint != NULL)) { indexConstraint.insert( indexConstraint.end(), sub->indexConstraint->begin(), sub->indexConstraint->end()); } if (sub != NULL) { assert(sub->declaration != NULL); return ResolveTypes::pickupIndexConstraint( sub->declaration, indexConstraint); } const UnconstrainedArrayType *ua = dynamic_cast(constrainedArray); assert(ua != NULL); return ua; } bool ResolveTypes::isConstraintArray(const TypeDeclaration *type) { switch (type->baseType) { case BASE_TYPE_ARRAY: break; default: return false; } std::list dr; ResolveTypes::pickupIndexConstraint(type, dr); return ! dr.empty(); } void ResolveTypes::process(ValDeclaration& node) { assert(node.subtypeIndic != NULL); this->typeCandidates.clear(); node.subtypeIndic->accept(*this); this->typeCandidates.clear(); if (node.init != NULL) { this->typeCandidates.insert(node.subtypeIndic); node.init->accept(*this); // for arrays, the node's subtype indication may // refer to an unconstraint array, and the bounds // are defined by the initializer. replace the // subtype indication then. if (this->needUniqueType(node)) { if (node.init->baseType != BASE_TYPE_ARRAY) { return; } // only constants may get the type inferred from the // initializer. if (node.storageClass != ValDeclaration::OBJ_CLASS_CONSTANT) { return; } // and for constants, *only* those that are not // interface elements. const ConstantDeclaration *c = dynamic_cast( &node); assert(c != NULL); if (! c->fixedValue) { return; } SubtypeIndication *si = dynamic_cast( node.init->type); assert(si != NULL); util::MiscUtil::terminate(node.subtypeIndic); node.subtypeIndic = si; #if 0 std::cerr << "replaced subtype with " << si << std::endl; std::cerr << "initializer is" << node.init << std::endl; #endif } } } void ResolveTypes::process(LibUnit &node) { //don't consider use- or library clauses //no need to call process here as well. //traverse to declarations. if (node.declarations != NULL) { this->listTraverse(*node.declarations); } } void ResolveTypes::process(ConditionedStat &node) { this->process(static_cast(node)); if (node.condition == NULL) { return; } // condition must be of type boolean const TypeDeclaration *boolean = this->symbolTable.getStdStandardType("boolean"); assert(boolean != NULL); this->typeCandidates.insert(boolean); node.condition->accept(*this); this->typeCandidates.clear(); } void ResolveTypes::process(SeqStat &node) { this->typeCandidates.clear(); } bool ResolveTypes::needUniqueType(AstNode &node) const { if (this->typeCandidates.size() == 1) { return true; } if (this->typeCandidates.empty()) { std::string msg = "Type error for <"; msg += util::MiscUtil::toString(node); msg += ">."; CompileError *ce = new CompileError(node, msg); ErrorRegistry::addError(ce); return false; } std::string msg = "Ambiguous Types for <"; msg += util::MiscUtil::toString(node); msg += ">."; CompileError *ce = new CompileError(node, msg); ErrorRegistry::addError(ce); return false; } bool ResolveTypes::needUniqueType(Expression &node) const { bool ret = this->needUniqueType(static_cast(node)); if (ret) { const TypeDeclaration *t = *this->typeCandidates.begin(); node.type = const_cast(t); node.baseType = t->baseType; } return ret; } void ResolveTypes::needNotEmpty(Location loc) { if (this->typeCandidates.empty()) { //FIXME: better error messages CompileError *ce = new CompileError( loc, "Type error."); ErrorRegistry::addError(ce); } } enum BaseType ResolveTypes::transformBaseType(enum BaseType rangeType, Location loc) { switch(rangeType) { case BASE_TYPE_INTEGER: return BASE_TYPE_RANGE_INT; case BASE_TYPE_REAL: return BASE_TYPE_RANGE_REAL; break; default: { CompileError *ce = new CompileError( loc, "Wrong base type for discrete range."); ErrorRegistry::addError(ce); } } return BASE_TYPE_UNSET; } void ResolveTypes::debugPrintTypes(const typeSetT &t) { for (typeSetT::const_iterator i = t.begin(); i != t.end(); i++) { std::cerr << "\tcand=" << *i << std::endl; } } DiscreteRange * ResolveTypes::determineIndexRangeAgg( const UnconstrainedArrayType *at, const std::list &assocs ) { universal_integer lowerBound; universal_integer upperBound; assert(at->indexTypes != NULL); // TODO currently only 1-dimensional arrays supported. assert(at->indexTypes->size() == 1); DiscreteRange *maxBounds = ResolveTypes::findRange(at->indexTypes->front()); assert(maxBounds != NULL); // TODO direction assert(maxBounds->direction == DiscreteRange::DIRECTION_UP); // start with a NULL range... lowerBound = maxBounds->getUpperBound(); upperBound = maxBounds->getLowerBound(); if ((! assocs.empty()) && (assocs.front()->choices == NULL)) { // positional aggregate. lower bound is indextype'left lowerBound = upperBound; upperBound = lowerBound + assocs.size() - 1; ConstInteger *lb = new ConstInteger(lowerBound, Location("context")); ConstInteger *ub = new ConstInteger(upperBound, Location("context")); return new DiscreteRange(lb, ub, DiscreteRange::DIRECTION_UP, Location("context")); } // aggregate with choices. for (std::list::const_iterator i = assocs.begin(); i != assocs.end(); i++) { if ((*i)->choices != NULL) { for (std::list::const_iterator j = (*i)->choices->begin(); j != (*i)->choices->end(); j++) { const ConstInteger *c = dynamic_cast(*j); assert(c != NULL); if (c->value < lowerBound) { lowerBound = c->value; } if (c->value > upperBound) { upperBound = c->value; } } } else { upperBound++; } } ConstInteger *lb = new ConstInteger(lowerBound, Location("context")); ConstInteger *ub = new ConstInteger(upperBound, Location("context")); return new DiscreteRange(lb, ub, DiscreteRange::DIRECTION_UP, Location("context")); } DiscreteRange * ResolveTypes::findRange(const TypeDeclaration *rangeType) { const SubtypeIndication *sub; sub = dynamic_cast(rangeType); if (sub != NULL) { if (sub->constraint != NULL) { return sub->constraint; } return ResolveTypes::findRange(sub->declaration); } const RangeConstraintType *base; base = dynamic_cast(rangeType); assert(base != NULL); assert(base->constraint != NULL); return base->constraint; } template ResolveTypes::TypeFilter::TypeFilter ( T &cands, typeSetT &wantTypes ) : candidates(cands), wantedTypes(wantTypes) { } const TypeDeclaration* ResolveTypes::SymbolFilter::operator()(Symbol *element) const { LookupTypes lat = LookupTypes(false, false); element->declaration.accept(lat); return lat.declaration; } template void ResolveTypes::TypeFilter::apply(void) { bool getAllPossibleTypes = this->wantedTypes.empty(); typeSetT possibleTypes = typeSetT(); for (typename T::iterator i = this->candidates.begin(); i != this->candidates.end(); /* nothing */) { //determine type declaration via () operator. const TypeDeclaration *t = (*this)(*i); if (t == NULL) { //operation turned out that candidate not plausible typename T::iterator j = i; i++; this->candidates.erase(j); continue; } if (getAllPossibleTypes) { // don't perform type checking. possibleTypes.insert(t); i++; continue; } if (this->checkType(t)) { possibleTypes.insert(t); i++; continue; } //resulting type not in wanted types. typename T::iterator j = i; i++; this->candidates.erase(j); } this->wantedTypes = possibleTypes; } template bool ResolveTypes::TypeFilter::checkType(const TypeDeclaration *t) const { assert(t); // must have wanted types, otherwise no type checking should be // performed but all possible types should get reported. assert(! this->wantedTypes.empty()); for (typeSetT::const_iterator i = this->wantedTypes.begin(); i != this->wantedTypes.end(); i++) { if (ResolveTypes::baseTypeEqual(**i, *t)) { return true; } } return false; } const TypeDeclaration* ResolveTypes::ProjectPositionalArg::operator()(Symbol* element) const { switch(element->type) { case SYMBOL_FUNCTION: case SYMBOL_PROCEDURE: break; default: /* only useful for functions/procedures */ //FIXME: port map/generic map aspects! assert(false); } Callable *c = dynamic_cast(&element->declaration); assert(c); assert(c->arguments); if (c->arguments->size() <= this->position) { return NULL; } std::list::const_iterator i = c->arguments->begin(); std::advance(i, this->position); const SubtypeIndication *s = (*i)->subtypeIndic; return s->declaration; } /** resolve the type of the source to a subscribed * type. * @param element source type * @return subscribed type. */ const TypeDeclaration* ResolveTypes::SubscriptFilter::operator()( typeSetT::value_type element ) const { // not an array? if (element->baseType != BASE_TYPE_ARRAY) { return NULL; } const SubtypeIndication *si = dynamic_cast( element); assert(si); const UnconstrainedArrayType *ua = dynamic_cast( ResolveTypes::findBaseType(si)); assert(ua); assert(ua->elementType); return ua->elementType; } const TypeDeclaration* ResolveTypes::IndexTypeFilter::operator()(typeSetT::value_type element) const { if (element->baseType != BASE_TYPE_ARRAY) { return NULL; } const UnconstrainedArrayType *array = dynamic_cast( ResolveTypes::findBaseType(element)); assert(array != NULL); assert(array->indexTypes != NULL); if (array->indexTypes->size() < this->nIdx) { return NULL; } bool found = false; std::list::const_iterator i = array->indexTypes->begin(); for (unsigned int j = 1; i != array->indexTypes->end(); i++, j++) { if (this->nIdx <= j) { found = true; break; } } if (found) { return *i; } return NULL; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/WarnUnused.cpp0000664000175000017500000000242711137610234021122 0ustar potyrapotyra/* $Id: WarnUnused.cpp 4323 2009-01-27 13:48:12Z potyra $ * WarnUnused: Visitor to emit a warning if a variable/constant/signal is * unused. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/WarnUnused.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/reporting/ErrorRegistry.hpp" namespace ast { void WarnUnused::process(ValDeclaration &node) { const char *kind = NULL; if (node.usage != ValDeclaration::USAGE_NONE) { return; } switch (node.storageClass) { case ValDeclaration::OBJ_CLASS_SIGNAL: kind = "signal"; break; case ValDeclaration::OBJ_CLASS_VARIABLE: kind = "variable"; break; case ValDeclaration::OBJ_CLASS_CONSTANT: /* skip */ return; case ValDeclaration::OBJ_CLASS_UNSPECIFIED: assert(false); break; } assert(node.name != NULL); std::string msg = std::string("Unused "); msg += kind; msg += " '"; msg += *node.name; msg += "'."; CompileError *ce = new CompileError(node, msg); /* FIXME add a warning, not an error */ ErrorRegistry::addWarning(ce); } }; fauhdlc-20130704/frontend/visitor/SimplifyExpressions.hpp0000664000175000017500000000453611266114422023077 0ustar potyrapotyra/* $Id: SimplifyExpressions.hpp 4824 2009-10-16 16:02:26Z potyra $ * * SimplifyExpressions: simplify nested expressions to simple expressions. * * Copyright (C) 2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SIMPLIFY_EXPRESSION_HPP_INCLUDED #define __SIMPLIFY_EXPRESSION_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" #include namespace ast { /** Simplify nested Expressions to simple Expressions * Dependencies: * TransformSigAssign */ class SimplifyExpressions : public TopDownVisitor { public: /** c'tor */ SimplifyExpressions() : simpleSeqs(std::list()), repexp(NULL) {} private: /** Visit a Process node. * @param node Process node that get's visited. */ virtual void visit(Process &node); /** Visit a VarAssignStat * @param node VarAssignStat node that get's visited. */ virtual void visit(VarAssignStat &node); /** Visit a SigAssignStat * @param node SigAssignStat node that get's visited. */ virtual void visit(SigAssignStat &node); /** Visit a CondalSigAssign node. * @param node CondalSigAssign node that get's visited. */ virtual void visit(CondalSigAssign &node); /** Visit a FunctionCall. * @param node FunctionCall node that get's visited. */ virtual void visit(FunctionCall &node); /** replace Expression with current replacement Expression, * if set. * @param e Expression to be eventually replaced. */ void setNode(Expression *&e); /** generate a temporary variable. * @param type type of the temporary. * @param name name (prefix) of the variable * @param suffix suffix of the variable (optional). * @return name referring to the generated variable. */ SimpleName *genTemporary( SubtypeIndication *type, std::string name, const char *suffix); /** List with simplified sequential statements to add before node. * This list will get added before the currently traversed sequential * statement. */ std::list simpleSeqs; /** simplifed Expression to replace the currently traversed * Expression. */ Expression *repexp; }; } /* namespace ast */ #endif /* __SIMPLIFY_EXPRESSION_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/ResolveAggregates.hpp0000664000175000017500000000626411137610234022450 0ustar potyrapotyra/* $Id: ResolveAggregates.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Resolve ranges of positional and named aggregates. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RESOLVE_AGGREGATES_HPP_INCLUDED #define __RESOLVE_AGGREGATES_HPP_INCLUDED #include "frontend/visitor/NullVisitor.hpp" #include "frontend/ast/Types.hpp" #include "frontend/misc/RangeSet.hpp" namespace ast { //! Resolve ranges of one positional and named aggregate. /** This visitor will resolve an array aggregate and set the range * member of an ElementAssociation to the result. * In case of erroneous specifications, errors will get reported. * * This class will only handle one single Aggregate. * Dependencies: * - TypeResolution * - ConstantPropagation */ class ResolveAggregates : public NullVisitor { public: //! c'tor /** @param arrayRange range of the target type. */ ResolveAggregates(const DiscreteRange &arrayRange); //! d'tor virtual ~ResolveAggregates(); /** Visit an Aggregate node. * @param node Aggregate node that get's visited. */ virtual void visit(Aggregate &node); private: /** visit a ElementAssociation * @param node node that get's visited. */ virtual void visit(ElementAssociation &node); /** Visit an Others node. * @param node Others node that get's visited. */ virtual void visit(Others &node); /** Visit a ConstInteger node. * @param node ConstInteger node that get's visited. */ virtual void visit(ConstInteger &node); /** Visit a DiscreteRange * @param node DiscreteRange node that get's visited. */ virtual void visit(DiscreteRange &node); //! Process a generic AstNode. /** Failmatch method. Must not be called. * * @param node AstNode */ virtual void process(AstNode &node); //! others node present in assocation list? bool haveOthers; //! named association list? bool named; //! positional association list? bool positional; //! was an error for a wrong others node reported already? bool othersErrorReported; //! current range for an ElementAssociation (or NULL) RangeSet *currentRange; //! produce sequences of numbers. class Sequencer { public: //! c'tor /** @param byRange range to construct the sequence from. */ Sequencer(const DiscreteRange &byRange); /** get the next number in the Sequence. Update the sequence * appropriately as well. * @return logical next number in the Sequence. */ universal_integer getNext(void); /** get the RangeSet containing elements which haven't been * taken yet. * @return new RangeSet containing all elements that haven't * been taken yet. Might be empty. */ RangeSet *getRemainder(void) const; //! underlying RangeSet RangeSet rs; private: //! direction of the sequence. enum DiscreteRange::Direction direction; }; //! sequencer for this array aggregate. Sequencer sequencer; }; }; /* namespace ast */ #endif /* __RESOLVE_AGGREGATES_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GCBuiltins.hpp0000664000175000017500000003105611173333203021035 0ustar potyrapotyra/* $Id: GCBuiltins.hpp 4493 2009-04-21 12:05:23Z potyra $ * * Generate intermediate code, intermediate code implementation of builtins. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GC_BUILTINS_HPP_INCLUDED #define __GC_BUILTINS_HPP_INCLUDED #include "frontend/visitor/GenCode.hpp" #include "frontend/misc/BuiltinSymbolTable.hpp" #include #include "intermediate/opcodes/OpCode.hpp" #include "intermediate/operands/RegisterFactory.hpp" #include "intermediate/opcodes/Sub.hpp" #include "intermediate/opcodes/Add.hpp" #include "intermediate/opcodes/IMul.hpp" #include "intermediate/opcodes/Div.hpp" namespace ast { //! abstract base class for an arbitrary builtin operator. /** GCBuiltins is the abstract base class for all builtin operators. * To generate code, the following functions must always get called: * * reset(); * generate code to evaluate first operand here ... * shortCutfirstOp(cc, firstOp); * generate code to evaluate the remaining operands here ... * emitCode(cc, operands); * * The operands parameter of emitCode must contain *all* operands. */ class GCBuiltins { public: //! virtual dummy d'tor. virtual ~GCBuiltins() {} //! generic abstract interface to emit code for a builtin function /** @param gc Code generator instance. * @param ops list of operands. * @return RegisterSet containing the result of the operands. */ virtual RegisterSet emitCode(GenCode &gc, std::list ops) const = 0; }; //! abstract base class for non-short-circuit operators class GCBuiltinsNoShortCircuit : public GCBuiltins { private: //! generic abstract interface to emit code for a builtin function /** @param gc Code generator instance. * @param ops list of operands. * @return RegisterSet containing the result of the operands. */ virtual RegisterSet emitCode(GenCode &gc, std::list ops) const; protected: //! emit code to calculate the result /** @param cc container to add generated code to. * @param ops RegisterSets containing the operands. * @return RegisterSet containing the result. */ virtual RegisterSet calculate( intermediate::CodeContainer &cc, std::list ops, std::list btl) const = 0; }; //! abstract base class for all binary short-circuit operators. class GCBuiltinsShortCircuit : public GCBuiltins { private: //! generic abstract interface to emit code for a builtin function /** * res = * if (left == ) { * goto out * } * if (right == ) { * goto out * res = < 1 - default > * } * * @param gc Code generator instance. * @param ops list of operands. * @return RegisterSet containing the result of the operands. */ virtual RegisterSet emitCode(GenCode &gc, std::list ops) const; protected: /** determine the default value, which gets used if the comparison * against getShortCut is equal. * @return the default value of the short circuit operator in the * range between 0 and 1. */ virtual universal_integer getDefault(void) const = 0; /** determine the value to check against, if the shortcut condition * matches. * @return if the operand is equal to the return value, the default * value will be used as result. */ virtual universal_integer getShortCut(void) const = 0; private: //! evaluate the result of one assocation and return it in an operand /** @param cc CodeContainer to add code to. * @param assoc association to evaluate. (FIXME interface ?) * @return operand containing the result */ static intermediate::Operand * evaluate(intermediate::CodeContainer *cc, AssociationElement &assoc); }; //! implementation of the "AND" short-circuit operator. class GCBuiltinsAnd : public GCBuiltinsShortCircuit { private: virtual universal_integer getDefault(void) const { return 0; } virtual universal_integer getShortCut(void) const { return 0; } }; //! implementation of the "OR" short-circuit operator. class GCBuiltinsOr : public GCBuiltinsShortCircuit { private: virtual universal_integer getDefault(void) const { return 1; } virtual universal_integer getShortCut(void) const { return 1; } }; //! implementation of the "NAND" short-circuit operator. class GCBuiltinsNand : public GCBuiltinsShortCircuit { private: virtual universal_integer getDefault(void) const { return 1; } virtual universal_integer getShortCut(void) const { return 0; } }; //! implementation of the "NOR" short-circuit operator. class GCBuiltinsNor : public GCBuiltinsShortCircuit { private: virtual universal_integer getDefault(void) const { return 0; } virtual universal_integer getShortCut(void) const { return 1; } }; //! no-short circuit unary operators for non-composite types. class GCBuiltinsUnop : public GCBuiltinsNoShortCircuit { private: //! emit code to calculate the result /** @param ops list of operands * @return RegisterSet containing the result. */ virtual RegisterSet calculate( intermediate::CodeContainer &cc, std::list ops, std::list btl) const; protected: //! calculate the result of the unary operator /** @param cc container to add generated code to. * @param op operand * @return Register containing the result. */ virtual intermediate::Register * calcUnOp( intermediate::CodeContainer &cc, intermediate::Operand *op) const = 0; }; //! no-short circuit binary opartors for non-composite types. class GCBuiltinsBinOp : public GCBuiltinsNoShortCircuit { private: //! emit code to calculate the result /** @param ops list of operands * @return RegisterSet containing the result. */ virtual RegisterSet calculate( intermediate::CodeContainer &cc, std::list ops, std::list btl) const; protected: //! calculate the result of the binary operator /** @param cc container to add generated code to. * @param left left operand * @param right right operand. * @return Register containing the result. */ virtual intermediate::Register * calcBinOp( intermediate::CodeContainer &cc, intermediate::Operand *left, intermediate::Operand *right) const = 0; }; //! unary not for boolean and bit. class GCBuiltinsNot : public GCBuiltinsUnop { private: //! emit code for an unary not (bit, boolean) virtual intermediate::Register * calcUnOp( intermediate::CodeContainer &cc, intermediate::Operand *op) const; }; //! xor for boolean and bit. class GCBuiltinsXor : public GCBuiltinsBinOp { protected: //! calculate the result of XOR /** @param cc container to add generated code to. * @param left left operand * @param right right operand. * @return Register containing the result. */ virtual intermediate::Register * calcBinOp( intermediate::CodeContainer &cc, intermediate::Operand *left, intermediate::Operand *right) const; }; //! xnor for boolean and bit. class GCBuiltinsXnor : public GCBuiltinsXor { private: //! calculate the result of XOR /** @param cc container to add generated code to. * @param left left operand * @param right right operand. * @return Register containing the result. */ virtual intermediate::Register * calcBinOp( intermediate::CodeContainer &cc, intermediate::Operand *left, intermediate::Operand *right) const; }; //! base class for comparison operators for non-composite types. class GCBuiltinsCompare : public GCBuiltinsBinOp { private: //! calculate the result of XOR /** @param cc container to add generated code to. * @param left left operand * @param right right operand. * @return Register containing the result. */ virtual intermediate::Register * calcBinOp( intermediate::CodeContainer &cc, intermediate::Operand *left, intermediate::Operand *right) const; protected: //! emit the comparison operation branch opcode. /** If the branch is not taken, 1-default value will be the result. * If the branch is taken, default value will be the result. * @param left left operand to compare * @param right right operand to compare * @param out branch target that uses the default value. * @return generated branch opcode. */ virtual intermediate::OpCode * emitBranch( intermediate::Operand *left, intermediate::Operand *right, intermediate::Label *out) const = 0; //! get the default value of the comparison operator. /** @return default value of the comparison operator. */ virtual universal_integer getDefaultValue(void) const = 0; }; //! equality for non-composite types. class GCBuiltinsEqual : public GCBuiltinsCompare { private: //! emit a je. virtual intermediate::OpCode * emitBranch( intermediate::Operand *left, intermediate::Operand *right, intermediate::Label *out) const; virtual universal_integer getDefaultValue(void) const { return VHDL_TRUE; } }; //! inequality for non-composite types. class GCBuiltinsInEqual : public GCBuiltinsCompare { private: //! emit a jne virtual intermediate::OpCode * emitBranch( intermediate::Operand *left, intermediate::Operand *right, intermediate::Label *out) const; virtual universal_integer getDefaultValue(void) const { return VHDL_TRUE; } }; //! less than for non-composite types. class GCBuiltinsLess : public GCBuiltinsCompare { private: //! emit a jb virtual intermediate::OpCode * emitBranch( intermediate::Operand *left, intermediate::Operand *right, intermediate::Label *out) const; virtual universal_integer getDefaultValue(void) const { return VHDL_TRUE; } }; //! less or equal for non-composite types. class GCBuiltinsLessEqual : public GCBuiltinsCompare { private: //! emit a jbe virtual intermediate::OpCode * emitBranch( intermediate::Operand *left, intermediate::Operand *right, intermediate::Label *out) const; virtual universal_integer getDefaultValue(void) const { return VHDL_TRUE; } }; //! greater than for non-composite types. class GCBuiltinsGreater : public GCBuiltinsCompare { private: //! emit a jbe virtual intermediate::OpCode * emitBranch( intermediate::Operand *left, intermediate::Operand *right, intermediate::Label *out) const; virtual universal_integer getDefaultValue(void) const { return VHDL_FALSE; } }; //! greater or equal for non-composite types. class GCBuiltinsGreaterEqual : public GCBuiltinsCompare { private: //! emit a jb virtual intermediate::OpCode * emitBranch( intermediate::Operand *left, intermediate::Operand *right, intermediate::Label *out) const; virtual universal_integer getDefaultValue(void) const { return VHDL_FALSE; } }; //! unary - (negation) for range constraint/physical types. class GCBuiltinsUnaryMinus : public GCBuiltinsUnop { private: //! calculate the result of the unary -. /** @param cc container to add generated code to. * @param op operand * @return Register containing the result. */ virtual intermediate::Register * calcUnOp( intermediate::CodeContainer &cc, intermediate::Operand *op) const; }; //! identity (unary plus) class GCBuiltinsIdentity : public GCBuiltins { private: virtual RegisterSet emitCode(GenCode &gc, std::list ops) const; }; //! unary abs for range constraint/physical types. class GCBuiltinsAbs : public GCBuiltinsUnop { private: //! calculate absolute value. virtual intermediate::Register * calcUnOp( intermediate::CodeContainer &cc, intermediate::Operand *op) const; }; //! template class for binary mathematical builtins /** template class for binary mathematical builtins that can use * a direct intermediate opcode for evaluation. */ template class GCBuiltinsBinaryMath : public GCBuiltinsBinOp { private: //calculate left + right virtual intermediate::Register * calcBinOp( intermediate::CodeContainer &cc, intermediate::Operand *left, intermediate::Operand *right) const { assert(left->type == right->type); intermediate::Register *result = cc.createRegister(left->type); T *operation = new T(left, right, result); cc.addCode(operation); return result; }; }; //! binary plus. class GCBuiltinsPlus : public GCBuiltinsBinaryMath { }; //! binary minus. class GCBuiltinsMinus : public GCBuiltinsBinaryMath { }; //! binary multiplication. class GCBuiltinsMult : public GCBuiltinsBinaryMath { }; //! binary division. class GCBuiltinsDiv : public GCBuiltinsBinaryMath { }; }; /* namespace ast */ #endif /* __GC_BUILTINS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GatherImplicits.cpp0000664000175000017500000002636411265642137022136 0ustar potyrapotyra/* $Id: GatherImplicits.cpp 4816 2009-10-15 15:48:47Z potyra $ * * Gather implicitly needed variables (e.g. drivers). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/GatherImplicits.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/LibUnit.hpp" #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/reporting/CompileError.hpp" #include "frontend/reporting/ErrorRegistry.hpp" // subprogram: out, inout / signal -> driver to process // signal gets assigned -> driver to process // // TODO it might be a more elegant idea to store ConstArrays // as constants (and Aggregates as well). namespace ast { GatherImplicits::GatherImplicits() : mode(VMODE_SOURCE), driverCounter(0), uhfCounter(0) { } void GatherImplicits::visit(SigAssignStat &node) { this->mode = VMODE_TARGET_SIGNAL; node.target->accept(*this); this->mode = VMODE_SOURCE; assert(node.waveForm); this->listTraverse(*node.waveForm); } void GatherImplicits::visit(VarAssignStat &node) { this->mode = VMODE_TARGET_VAR; node.target->accept(*this); this->mode = VMODE_SOURCE; node.source->accept(*this); } void GatherImplicits::visit(SimpleName &node) { switch(this->mode) { case VMODE_TARGET_SIGNAL: { SignalDeclaration *sig = dynamic_cast( node.getDeclaration()); if (sig == NULL) { CompileError *err = new CompileError(node, "Target of signal assignment not a signal."); ErrorRegistry::addError(err); return; } node.driver = this->registerDriver(*sig, node); break; } case VMODE_TARGET_VAR: { // only check, if it is in fact a VarDeclaration. const VarDeclaration *var = dynamic_cast( node.getDeclaration()); if (var == NULL) { CompileError *err = new CompileError(node, "Target of a variable assignment not a " "variable."); ErrorRegistry::addError(err); } break; } case VMODE_SOURCE: // nothing to check break; } } void GatherImplicits::visit(Process &node) { assert(this->drivers.empty()); formalMapT formalBackup = this->formals; this->formals.clear(); assert(node.declarations != NULL); if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); } assert(node.drivers.empty()); for (std::map::const_iterator i = this->drivers.begin(); i != this->drivers.end(); i++) { node.drivers.push_back(i->second); } for (formalMapT::const_iterator i = this->formals.begin(); i != this->formals.end(); i++) { node.declarations->push_back(i->second.first); } this->formals = formalBackup; this->drivers.clear(); } void GatherImplicits::visit(FunctionCall &node) { // type resolution must have happened before assert(node.definition != NULL); switch(this->mode) { case VMODE_TARGET_SIGNAL: case VMODE_TARGET_VAR: { CompileError *err = new CompileError(node, "Invalid lvalue in assignment"); ErrorRegistry::addError(err); return; } default: // nothing to do break; } if (node.arguments == NULL) { return; } if (node.definition->arguments == NULL) { return; } std::list::const_iterator i = node.definition->arguments->begin(); for (std::list::const_iterator j = node.arguments->begin(); j != node.arguments->end(); i++, j++) { assert(i != node.definition->arguments->end()); switch ((*i)->storageClass) { case ValDeclaration::OBJ_CLASS_CONSTANT: // need hidden formals for composite types only. assert((*i)->subtypeIndic != NULL); switch ((*i)->subtypeIndic->baseType) { case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: (*j)->hiddenFormal = this->registerFormal(*i, (*j)->actual->type); break; default: break; } break; default: break; } } } void GatherImplicits::visit(ProcCallStat &node) { assert(node.definition != NULL); if (node.definition->arguments == NULL) { return; } // TODO register implicit formals as necessary. if (node.arguments == NULL) { return; } assert(node.definition->arguments != NULL); std::list::const_iterator f = node.definition->arguments->begin(); // pickup drivers from actuals for (std::list::iterator i = node.arguments->begin(); i != node.arguments->end(); i++, f++) { this->pickupImplicits(**f, **i); } } void GatherImplicits::pickupImplicits( ValDeclaration &formalDecl, AssociationElement &assoc ) { switch (formalDecl.mode) { case ValDeclaration::MODE_OUT: case ValDeclaration::MODE_INOUT: switch (formalDecl.storageClass) { case ValDeclaration::OBJ_CLASS_SIGNAL: this->mode = VMODE_TARGET_SIGNAL; break; case ValDeclaration::OBJ_CLASS_VARIABLE: this->mode = VMODE_TARGET_VAR; break; default: break; } default: break; } switch (formalDecl.storageClass) { case ValDeclaration::OBJ_CLASS_CONSTANT: assert(formalDecl.subtypeIndic != NULL); // already handled by NormalizeAssocs, if there's no // association in the first place. // (then an association must have been created anyway, // together with a hidden formal). if (assoc.hiddenFormal != NULL) { this->mode = VMODE_SOURCE; return; } switch (formalDecl.subtypeIndic->baseType) { case BASE_TYPE_RECORD: assoc.hiddenFormal = this->registerFormal(&formalDecl, assoc.actual->type); break; case BASE_TYPE_ARRAY: { // if the actual is an unconstraint array, // we have a pointer to storage space already. // Hence we'll only need a hiddenFormal, if // there's a constraint array. bool isConstraint = ResolveTypes::isConstraintArray( assoc.actual->type); if (! isConstraint) { break; } assoc.hiddenFormal = this->registerFormal(&formalDecl, assoc.actual->type); break; } default: break; } break; default: break; } assoc.actual->accept(*this); this->mode = VMODE_SOURCE; } void GatherImplicits::visit(FunctionDeclaration &node) { this->processCallable(node); } void GatherImplicits::visit(ProcedureDeclaration &node) { this->processCallable(node); } void GatherImplicits::processCallable(Callable &node) { assert(this->drivers.empty()); formalMapT formalBackup = this->formals; this->formals.clear(); if (node.definition != NULL) { node.definition->accept(*this); } // FIXME that's still ugly and will fail for procedures that // are defined in a process and directly modify signals. if (node.arguments != NULL) { for (std::list::const_iterator i = node.arguments->begin(); i != node.arguments->end(); i++) { switch ((*i)->mode) { case ValDeclaration::MODE_IN: break; case ValDeclaration::MODE_OUT: case ValDeclaration::MODE_INOUT: switch ((*i)->storageClass) { case ValDeclaration::OBJ_CLASS_SIGNAL: this->registerDriver(**i, SYMBOL_PARAMETER); break; default: break; } break; } } } for (std::map::const_iterator i = this->drivers.begin(); i != this->drivers.end(); i++) { node.drivers.push_back(i->second); } // FIXME do s.th. with formals! this->formals = formalBackup; this->drivers.clear(); } void GatherImplicits::process(LibUnit &node) { if (node.declarations != NULL) { this->listTraverse(*node.declarations); } } void GatherImplicits::visit(Architecture &node) { assert(this->drivers.empty()); assert(this->formals.empty()); this->process(node); if (node.concurrentStats != NULL) { this->listTraverse(*node.concurrentStats); } for (formalMapT::const_iterator i = this->formals.begin(); i != this->formals.end(); i++) { node.declarations->push_back(i->second.first); } this->drivers.clear(); this->formals.clear(); } void GatherImplicits::visit(CompInstStat &node) { // at this point, association lists have already been normalized assert(node.genericMap != NULL); assert(node.entity != NULL); assert(node.entity->generics != NULL); std::list::const_iterator g = node.entity->generics->begin(); for (std::list::iterator i = node.genericMap->begin(); i != node.genericMap->end(); i++, g++) { this->pickupImplicits(**g, **i); } } Driver * GatherImplicits::registerDriver(const SignalDeclaration &decl, SimpleName &n) { std::map::const_iterator i = this->drivers.find(&decl); if (i != this->drivers.end()) { // driver registered already return i->second; } // driver not yet present. Driver *d = new Driver(decl, this->driverCounter, &n); this->driverCounter++; this->drivers[&decl] = d; return d; } void GatherImplicits::registerDriver(ValDeclaration &decl, enum symType t) { // must not throw an exception, otherwise logic error SignalDeclaration &d = dynamic_cast(decl); std::map::const_iterator i = this->drivers.find(&d); if (i != this->drivers.end()) { // driver registered already return; } Symbol *sym = new Symbol(d.name, t, NULL, d); std::list cands = std::list(); cands.push_back(sym); SimpleName *sn = new SimpleName(new std::string(*d.name), cands, d.location); this->registerDriver(d, *sn); } SimpleName * GatherImplicits::registerFormal( const ValDeclaration *formal, TypeDeclaration *actualType ) { formalMapT::const_iterator i = this->formals.find(formal); if (i != this->formals.end()) { return i->second.second; } std::string *name = new std::string("__"); *name += *formal->name; *name += "__hidden_formal__"; SubtypeIndication *si; bool isUnconstraint = formal->isUnconstraint(); if (isUnconstraint) { si = dynamic_cast(actualType); assert(si != NULL); *name += util::MiscUtil::toString(this->uhfCounter); this->uhfCounter++; } else { si = formal->subtypeIndic; } // generate a ValDeclaration VarDeclaration *hidden = new VarDeclaration( formal->mode, name, NULL, si, Location("__hidden_formal__")); Symbol *sym = new Symbol(name, SYMBOL_VARIABLE, NULL, *hidden); std::list cands = std::list(); cands.push_back(sym); SimpleName *ref = new SimpleName(new std::string(*name), cands, Location("__builtin__")); if (isUnconstraint) { // need seperate entries for each actual of a // unconstraint formal, since the storage size // can differs. this->formals[hidden] = std::pair(hidden, ref); } else { // but only one entry for a constraint formal, since // the storage size is fixed. this->formals[formal] = std::pair(hidden, ref); } return ref; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/SetPathName.cpp0000664000175000017500000001035411137610234021176 0ustar potyrapotyra/* $Id: SetPathName.cpp 4323 2009-01-27 13:48:12Z potyra $ * * For different symbol bearing nodes, determine the full vhdl path name. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/SetPathName.hpp" #include #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/ast/Library.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "util/MiscUtil.hpp" namespace ast { SetPathName::SetPathName() : anonCounter(0) { } void SetPathName::visit(Library &node) { this->currentPath.push_back(*node.name); this->listTraverse(node.units); this->currentPath.pop_back(); } void SetPathName::visit(Entity &node) { //FIXME? LRM, p202 doesn't show the library path name? this->currentPath.push_back(*node.name); if (node.generics != NULL) { this->listTraverse(*node.generics); } if (node.ports != NULL) { this->listTraverse(*node.ports); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); } this->currentPath.pop_back(); this->process(node); } void SetPathName::visit(Architecture &node) { assert(node.entity != NULL); this->currentPath.push_back(*node.entity->name); //skip use and library clauses if (node.declarations != NULL) { this->listTraverse(*node.declarations); } //FIXME two architectures for same entity not handled. this->anonCounter = 0; if (node.concurrentStats != NULL) { this->listTraverse(*node.concurrentStats); } this->currentPath.pop_back(); this->process(node); } void SetPathName::visit(Package &node) { assert(node.name != NULL); this->currentPath.push_back(*node.name); TopDownVisitor::visit(node); this->currentPath.pop_back(); this->process(node); } void SetPathName::visit(Process &node) { if (node.name != NULL) { this->process(node); this->currentPath.push_back(*node.name); } else { std::string anonName = "__anonymous__" + util::MiscUtil::toString(this->anonCounter); this->anonCounter++; this->currentPath.push_back(anonName); node.pathName = this->getPath(); } if (node.declarations != NULL) { this->listTraverse(*node.declarations); } if (node.seqStats != NULL) { this->listTraverse(*node.seqStats); } this->currentPath.pop_back(); } void SetPathName::visit(FunctionDeclaration &node) { assert(node.returnType != NULL); const TypeDeclaration *returnType = ResolveTypes::findBaseType(node.returnType); assert(returnType != NULL); std::string suffix = "return " + *(returnType->name); this->processCallable(node, &suffix); } void SetPathName::visit(ProcedureDeclaration &node) { this->processCallable(node, NULL); } void SetPathName::process(SymbolDeclaration &node) { if (node.name != NULL) { node.pathName = this->getPath() + *node.name + ':'; } } void SetPathName::processCallable(Callable &node, const std::string *pSuffix) { std::string argPathName = *node.name; assert(node.arguments != NULL); argPathName += "["; for (std::list::const_iterator i = node.arguments->begin(); i != node.arguments->end(); i++) { if (i != node.arguments->begin()) { argPathName += ","; } const TypeDeclaration *baseType = ResolveTypes::findBaseType((*i)->subtypeIndic); argPathName += *baseType->name; } if (! (node.arguments->empty() || (pSuffix == NULL))) { argPathName += ' '; } if (pSuffix != NULL) { argPathName += (*pSuffix); } argPathName += "]"; this->currentPath.push_back(argPathName); node.pathName = this->getPath(); this->listTraverse(*node.arguments); if (node.definition != NULL) { node.definition->accept(*this); } this->currentPath.pop_back(); } std::string SetPathName::getPath(void) const { std::string ret; for (std::list::const_iterator i = this->currentPath.begin(); i != this->currentPath.end(); i++) { ret += ":"; ret += *i; } ret += ":"; return ret; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/GCArrays.hpp0000664000175000017500000001653311245250315020512 0ustar potyrapotyra/* $Id: GCArrays.hpp 4608 2009-08-26 15:12:13Z potyra $ * * Generate intermediate code, array specific parts. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GC_ARRAYS_HPP_INCLUDED #define __GC_ARRAYS_HPP_INCLUDED #include #include "intermediate/container/CodeContainer.hpp" #include "intermediate/container/LabelFactory.hpp" #include "intermediate/operands/Register.hpp" #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/visitor/GCTypes.hpp" namespace ast { //! ArrayHandling can subscribe to arrays. class ArrayHandling { public: /** @param at array type declaration (should be an unconstraint array) * @param b base pointer of the array. * @param container container to add generated code to. * @param lbounds operands containing the left bounds for each * dimension of the unconstraint array. * @param rbounds operands containing the right bounds for * each dimension of the unconstraint array. * @param directs operands containing the direction (1/-1) for each * dimension of the unconstraint array. */ ArrayHandling( TypeDeclaration *at, intermediate::Operand *b, intermediate::CodeContainer &container, std::list lbounds, std::list rbounds, std::list directs); //! d'tor ~ArrayHandling(); intermediate::Register * subscribe(std::list relativeIndices); private: /** calculate the list of factors */ void factorize(void); /** factors with which each dimennsion must be multiplied. */ std::list dimensionFactors; protected: /** array type */ TypeDeclaration *arrayType; private: /** pointer to start of array */ intermediate::Operand *base; protected: /** container, to which code will be added */ intermediate::CodeContainer &cc; /** list of left bounds for each dimension */ std::list leftBounds; /** list of right bounds for each dimension */ std::list rightBounds; /** list of directions (1=to, -1=downto) for each dimenstion */ std::list directions; private: /** intermediate code type of array */ intermediate::Type *itype; protected: /** type of final elements. (doesn't necessary match resulting type * of a subscription, e.g. in cases of an array of an array, where * only the first array is subscribed. This always refers to a type * which is not an array. */ TypeDeclaration *elementType; /** list of indices */ std::list indices; public: /** transform the index to a zero-based index (useful for ConstArray) * based on the IndexConstraint of arrayType. * @param arrayType type of the constraint array. * @param idx index relative to constraint type. * @return zero-based index, suitable for ConstArray. */ static universal_integer transform_idx( const TypeDeclaration *arrayType, universal_integer idx ); }; //! generic array handling to iterate over all elements of an array. /** Generic array handling which can iterate over all elements of an array, * in case the bounds are statically known. * Abstract class, implementors need to implement iterateBody. */ class StaticArrayIterate : public ArrayHandling { public: /** c'tor * @param at Array type declaration (must not be an unonstraint array * @param b register with the base pointer of the array * @param container container to add generated code to. */ StaticArrayIterate( TypeDeclaration *at, intermediate::Operand *b, intermediate::CodeContainer &container ) : ArrayHandling( at, b, container, std::list(), std::list(), std::list()) {} /** dummy virtual d'tor */ virtual ~StaticArrayIterate() {} /** iterate over all elements of the array, calling iterateBody for * each */ void iterate(void); protected: /** called for each element during for an iteration. * @param element pointer to the element in question. * @param indices list of indices denoting the element. */ virtual void iterateBody( intermediate::Register *element, std::list indices ) = 0; private: /** check if all counters have reached ubounds. * @param counters loop counters. * @param rbounds right bounds of the array. * @param directions directions of the array (-1, 1). * @return true, if all counters are the same as the respective * right bounds, otherwise false. */ static bool checkLoop( const std::list &counters, const std::list &rbounds, const std::list &directions); /** increase the counters to advance to the next element. * @param counters loop counters to be increased. * @param lbounds corresponding left bounds. * @param rbounds corresponding right bounds. * @param directions directions (-1, 1) of the array, which are * used as a step factor here. */ static void incCounters( std::list &counters, const std::list &lbounds, const std::list &rbounds, const std::list &directions); }; //! iterate over arrays /** This class can generate loop code to iterate over an array. * It works for both arrays, where the bounds are known statically, as * well for ones where the bounds are known dynamically. */ class ArrayIterate : public ArrayHandling { public: /** @param at array type declaration (should be an unconstraint array) * @param b base pointer of the array. * @param container container to add generated code to. * @param lbounds operands containing the left bounds for each * dimension of the unconstraint array. * @param rbounds operands containing the right bounds for * each dimension of the unconstraint array. * @param directs directions (-1, 1) of the dimensions. */ ArrayIterate( TypeDeclaration *at, intermediate::Operand *b, intermediate::CodeContainer &container, std::list lbounds, std::list rbounds, std::list directs ) : ArrayHandling(at, b, container, lbounds, rbounds, directs), loop(intermediate::LabelFactory::getLabel("loop")) {} //! dummy d'tor virtual ~ArrayIterate() {} /** iterate over all elements of the array */ void iterate(void); protected: /** called for one element of the iteration in the place of the body * of the iteration. * @param element pointer to the element in question. * @param indices list of indices denoting the element (rel. offsets) */ virtual void iterateBody( intermediate::Register *element, std::list indices ) = 0; private: //! initialize the counters with the left bounds. void initCounters(void); //! increase the counters void incCounters(void); /** list of counters for dimensions. */ std::list counters; /** loop label. */ intermediate::Label *loop; }; }; /* namespace ast */ #endif /* __GC_ARRAYS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/NullVisitor.hpp0000664000175000017500000002667311243477217021351 0ustar potyrapotyra/* $Id: NullVisitor.hpp 4555 2009-08-21 11:01:35Z potyra $ * NullVisitor: base class for visitors that don't want any default traversal. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NULL_VISITOR_HPP_INCLUDED #define __NULL_VISITOR_HPP_INCLUDED #include "frontend/visitor/Visitor.hpp" namespace ast { //! Visitor, that doesn't traverse. /** This visitor doesn't traverse in any way. It only calls the * appropriate process methods. */ class NullVisitor : public Visitor { public: /** dummy d'tor */ virtual ~NullVisitor() {} /** visit a ElementAssociation * @param node node that get's visited. */ virtual void visit(ElementAssociation &node); /** visit a ConstReal * @param node node that get's visited. */ virtual void visit(ConstReal &node); /** visit a SimpleName * @param node node that get's visited. */ virtual void visit(SimpleName &node); /** visit a TemporaryName * @param node node that get's visited. */ virtual void visit(TemporaryName &node); /** visit a SelectedName * @param node node that get's visited. */ virtual void visit(SelectedName &node); /** visit a AttributeName * @param node node that get's visited. */ virtual void visit(AttributeName &node); /** Visit an Entity declaration. * @param node Entity Declaration node that get's visited. */ virtual void visit(Entity &node); /** Visit an Signal declaration. * @param node SignalDeclaration node that get's visited. */ virtual void visit(SignalDeclaration &node); /** Visit an Constant declaration. * @param node ConstantDeclaration node that get's visited. */ virtual void visit(ConstantDeclaration &node); /** Visit an FunctionCall. * @param node FunctionCall node that get's visited. */ virtual void visit(FunctionCall &node); /** Visit an IfStat. * @param node IfStat node that get's visited. */ virtual void visit(IfStat &node); /** Visit an NullStat. * @param node IfStat node that get's visited. */ virtual void visit(NullStat &node); /** Visit a ForLoopStat * @param node ForLoopStat node that get's visited. */ virtual void visit(ForLoopStat &node); /** Visit a WhileLoopStat * @param node WhileLoopStat node that get's visited. */ virtual void visit(WhileLoopStat &node); /** Visit a NextStat * @param node NextStat node that get's visited. */ virtual void visit(NextStat &node); /** Visit a VarAssignStat * @param node VarAssignStat node that get's visited. */ virtual void visit(VarAssignStat &node); /** Visit a WaitStat * @param node WaitStat node that get's visited. */ virtual void visit(WaitStat &node); /** Visit a ExitStat * @param node ExitStat node that get's visited. */ virtual void visit(ExitStat &node); /** Visit a SigAssignStat * @param node SigAssignStat node that get's visited. */ virtual void visit(SigAssignStat &node); /** Visit a WaveFormElem * @param node WaveFormElem node that get's visited. */ virtual void visit(WaveFormElem &node); /** Visit a ReturnStat * @param node ReturnStat node that get's visited. */ virtual void visit(ReturnStat &node); /** Visit a ProcCallStat * @param node ReturnStat node that get's visited. */ virtual void visit(ProcCallStat &node); /** Visit a AssertStat * @param node AssertStat node that get's visited. */ virtual void visit(AssertStat &node); /** Visit a VarDeclaration * @param node VarDeclaration node that get's visited. */ virtual void visit(VarDeclaration &node); /** Visit a DiscreteRange * @param node DiscreteRange node that get's visited. */ virtual void visit(DiscreteRange &node); /** Visit a CaseStat * @param node CaseStat node that get's visited. */ virtual void visit(CaseStat &node); /** Visit a CaseAlternative * @param node CaseAlternative node that get's visited. */ virtual void visit(CaseAlternative &node); /** Visit an Others node. * @param node Others node that get's visited. */ virtual void visit(Others &node); /** Visit a Architecture node. * @param node Architecture node that get's visited. */ virtual void visit(Architecture &node); /** Visit a AssociationElement node. * @param node AssociationElement node that get's visited. */ virtual void visit(AssociationElement &node); /** Visit a FunctionDeclaration node. * @param node FunctionDeclaration node that get's visited. */ virtual void visit(FunctionDeclaration &node); /** Visit a ProcedureDeclaration node. * @param node ProcedureDeclaration node that get's visited. */ virtual void visit(ProcedureDeclaration &node); /** Visit a CompInstStat node. * @param node CompInstStat node that get's visited. */ virtual void visit(CompInstStat &node); /** Visit a Package node. * @param node Package node that get's visited. */ virtual void visit(Package &node); /** Visit a PackageBody node. * @param node PackageBody node that get's visited. */ virtual void visit(PackageBody &node); /** Visit a Process node. * @param node Process node that get's visited. */ virtual void visit(Process &node); /** Visit a SubprogBody node. * @param node SubprogBody node that get's visited. */ virtual void visit(SubprogBody &node); /** Visit a CondalSigAssign node. * @param node CondalSigAssign node that get's visited. */ virtual void visit(CondalSigAssign &node); /** Visit an EnumerationType node. * @param node EnumerationType node that get's visited. */ virtual void visit(EnumerationType &node); /** Visit an PhysicalType node. * @param node PhysicalType node that get's visited. */ virtual void visit(PhysicalType &node); /** Visit an PhysicalTypeUnit node. * @param node PhysicalTypeUnit node that get's visited. */ virtual void visit(PhysicalTypeUnit &node); /** Visit an RangeConstraintType node. * @param node RangeConstraintType node that get's visited. */ virtual void visit(RangeConstraintType &node); /** Visit an UnconstrainedArrayType node. * @param node UnconstrainedArrayType node that get's visited. */ virtual void visit(UnconstrainedArrayType &node); /** Visit an RecordType node. * @param node RecordType node that get's visited. */ virtual void visit(RecordType &node); /** Visit an RecordTypeElement node. * @param node RecordTypeElement node that get's visited. */ virtual void visit(RecordTypeElement &node); /** Visit an Aggregate node. * @param node Aggregate node that get's visited. */ virtual void visit(Aggregate &node); /** Visit a SubtypeIndication node. * @param node SubtypeIndication node that get's visited. */ virtual void visit(SubtypeIndication &node); /** Visit a Library node. * @param node Library node that get's visited. */ virtual void visit(Library &node); /** Visit a LibraryList node. * @param node LibraryList node that get's visited. */ virtual void visit(LibraryList &node); /** Visit a Slice node. * @param node Slice node that get's visited. */ virtual void visit(Slice &node); /** Visit a ConstInteger node. * @param node ConstInteger node that get's visited. */ virtual void visit(ConstInteger &node); /** Visit a ConstArray node. * @param node ConstArray node that get's visited. */ virtual void visit(ConstArray &node); /** Visit a Subscript node. * @param node Subscript node that get's visited. */ virtual void visit(Subscript &node); /** Visit a TypeConversion node. * @param node TypeConversion node that get's visited. */ virtual void visit(TypeConversion &node); /** Visit an AttributeDeclaration node. * @param node AttributeDeclaration node that gets visited. */ virtual void visit(AttributeDeclaration &node); /** Visit an AttributeSpecification node. * @param node AttributeSpecification node that gets visited. */ virtual void visit(AttributeSpecification &node); protected: using Visitor::process; //! Process a generic ValDeclaration. /** This function will get called for each ValDeclaration (or class * derived from ValDeclaration) that get's visited. * * @param node ValDeclaration instance. */ virtual void process(ValDeclaration &node); //! Process a generic SymbolDeclaration. /** This function will get called for each SymbolDeclaration (or class * derived from SymbolDeclaration) that get's visited. * * @param node SymbolDeclaration instance. */ virtual void process(SymbolDeclaration &node); //! Process a generic Expression. /** This function will get called for each Expression (or class * derived from Expression) that get's visited. * * @param node Expression instance. */ virtual void process(Expression &node); //! Process a generic SeqStat. /** This function will get called for each SeqStat (or class * derived from SeqStat) that get's visited. * * @param node SeqStat instance. */ virtual void process(SeqStat& node); //! Process a generic LoopStat. /** This function will get called for each LoopStat (or class * derived from LoopStat) that get's visited. * * @param node LoopStat instance. */ virtual void process(LoopStat& node); //! Process a generic ConditionedStat. /** This function will get called for each ConditionedStat (or class * derived from ConditionedStat) that get's visited. * * @param node ConditionedStat instance. */ virtual void process(ConditionedStat& node); //! Process a generic Callable. /** This function will get called for each Callable (or class * derived from Callable) that get's visited. * * @param node Callable instance. */ virtual void process(Callable& node); //! Process a generic LibUnit. /** This function will get called for each LibUnit (or class * derived from LibUnit) that get's visited. * * @param node LibUnit instance. */ virtual void process(LibUnit& node); //! Process a generic TypeDeclaration. /** This function will get called for each TypeDeclaration (or class * derived from TypeDeclaration) that get's visited. * * @param node TypeDeclaration instance. */ virtual void process(TypeDeclaration &node); //! Process a generic PrefixedName. /** This function will get called for each PrefixedName (or class * derived from PrefixedName) that get's visited. * * @param node PrefixedName instance. */ virtual void process(PrefixedName &node); //! Process a generic Name. /** This function will get called for each Name (or class * derived from Name) that get's visited. * * @param node Name instance. */ virtual void process(Name &node); //! Process a AttributableDeclaration. /** This function will get called for each AttributableDeclaration * (or class derived from it) that gets visited. * * @param node AttributableDeclaration instance. */ virtual void process(AttributableDeclaration &node); }; }; /* namespace ast */ #endif /* __NULL_VISITOR_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/WaitConditions.hpp0000664000175000017500000000315011137610234021764 0ustar potyrapotyra/* $Id: WaitConditions.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Wait conditions: Checks sensitivity lists and wait statements, and * transforms sensitivity lists into wait statements. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __WAIT_CONDITIONS_HPP_INCLUDED #define __WAIT_CONDITIONS_HPP_INCLUDED #include #include "frontend/visitor/TopDownVisitor.hpp" namespace ast { //! Check/generate wait conditions from sensitivity lists. /** dependencies: * - ResolveTypes (overload resolution must have happened) */ class WaitConditions : public TopDownVisitor { public: //! c'tor. WaitConditions(); /** Visit a Process node. * @param node Process node that get's visited. */ virtual void visit(Process &node); /** Visit a WaitStat * @param node WaitStat node that get's visited. */ virtual void visit(WaitStat &node); /** Visit a ProcCallStat * * @param node ReturnStat node that get's visited. */ virtual void visit(ProcCallStat &node); /** Visit a ProcedureDeclaration node. * @param node ProcedureDeclaration node that get's visited. */ virtual void visit(ProcedureDeclaration &node); private: //! sensitivity list of currently examined process (or NULL) std::list *sensList; //! wait statement found in the process? bool waitSeen; }; }; /* namespace ast */ #endif /* __WAIT_CONDITIONS_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/WarnUnused.hpp0000664000175000017500000000205011137610234021117 0ustar potyrapotyra/* $Id: WarnUnused.hpp 4323 2009-01-27 13:48:12Z potyra $ * WarnUnused: Visitor to emit a warning if a variable/constant/signal is * unused. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __WARN_UNUSED_HPP_INCLUDED #define __WARN_UNUSED_HPP_INCLUDED #include "frontend/visitor/TopDownVisitor.hpp" namespace ast { //! warn if variables/signals are unused. class WarnUnused : public TopDownVisitor { public: //! c'tor WarnUnused() {} private: //! Process a generic ValDeclaration. /** This function will get called for each ValDeclaration (or class * derived from ValDeclaration) that get's visited. * * @param node ValDeclaration instance. */ virtual void process(ValDeclaration &node); }; }; /* namespace ast */ #endif /* __WARN_UNUSED_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/NullVisitor.cpp0000664000175000017500000002047411243477217021335 0ustar potyrapotyra/* $Id: NullVisitor.cpp 4555 2009-08-21 11:01:35Z potyra $ * NullVisitor: base class for visitors that don't want any default traversal. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/NullVisitor.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/ConstArray.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/IfStat.hpp" #include "frontend/ast/NullStat.hpp" #include "frontend/ast/ForLoopStat.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/NextStat.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/ExitStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/WaveFormElem.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/AssertStat.hpp" #include "frontend/ast/VarDeclaration.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/CaseStat.hpp" #include "frontend/ast/CaseAlternative.hpp" #include "frontend/ast/Others.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/PackageBody.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/SubprogBody.hpp" #include "frontend/ast/CondalSigAssign.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/ElementAssociation.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/ast/Library.hpp" #include "frontend/ast/LibraryList.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/TypeConversion.hpp" #include "frontend/ast/AttributeDeclaration.hpp" #include "frontend/ast/AttributeSpecification.hpp" namespace ast { void NullVisitor::visit(ElementAssociation& node) { this->process(node); } void NullVisitor::visit(ConstReal& node) { this->process(node); } void NullVisitor::visit(ConstArray &node) { this->process(node); } void NullVisitor::visit(SimpleName &node) { this->process(node); } void NullVisitor::visit(TemporaryName &node) { this->process(node); } void NullVisitor::visit(SelectedName &node) { this->process(node); } void NullVisitor::visit(AttributeName &node) { this->process(node); } void NullVisitor::visit(Entity& node) { this->process(node); } void NullVisitor::visit(LibraryList& node) { this->process(node); } void NullVisitor::visit(SignalDeclaration& node) { this->process(node); } void NullVisitor::visit(ConstantDeclaration& node) { this->process(node); } void NullVisitor::visit(FunctionCall& node) { this->process(node); } void NullVisitor::visit(IfStat& node) { this->process(node); } void NullVisitor::visit(NullStat& node) { this->process(node); } void NullVisitor::visit(ForLoopStat& node) { this->process(node); } void NullVisitor::visit(WhileLoopStat& node) { this->process(node); } void NullVisitor::visit(NextStat& node) { this->process(node); } void NullVisitor::visit(VarAssignStat& node) { this->process(node); } void NullVisitor::visit(WaitStat& node) { this->process(node); } void NullVisitor::visit(ExitStat& node) { this->process(node); } void NullVisitor::visit(SigAssignStat& node) { this->process(node); } void NullVisitor::visit(WaveFormElem& node) { this->process(node); } void NullVisitor::visit(ReturnStat& node) { this->process(node); } void NullVisitor::visit(ProcCallStat& node) { this->process(node); } void NullVisitor::visit(AssertStat& node) { this->process(node); } void NullVisitor::visit(VarDeclaration& node) { this->process(node); } void NullVisitor::visit(DiscreteRange& node) { this->process(node); } void NullVisitor::visit(CaseStat& node) { this->process(node); } void NullVisitor::visit(CaseAlternative& node) { this->process(node); } void NullVisitor::visit(Others& node) { this->process(node); } void NullVisitor::visit(Architecture& node) { this->process(node); } void NullVisitor::visit(AssociationElement& node) { this->process(node); } void NullVisitor::visit(FunctionDeclaration& node) { this->process(node); } void NullVisitor::visit(ProcedureDeclaration& node) { this->process(node); } void NullVisitor::visit(CompInstStat& node) { this->process(node); } void NullVisitor::visit(Package& node) { this->process(node); } void NullVisitor::visit(PackageBody& node) { this->process(node); } void NullVisitor::visit(Process& node) { this->process(node); } void NullVisitor::visit(SubprogBody& node) { this->process(node); } void NullVisitor::visit(CondalSigAssign& node) { this->process(node); } void NullVisitor::visit(EnumerationType& node) { this->process(node); } void NullVisitor::visit(PhysicalType& node) { this->process(node); } void NullVisitor::visit(PhysicalTypeUnit& node) { this->process(node); } void NullVisitor::visit(RangeConstraintType& node) { this->process(node); } void NullVisitor::visit(UnconstrainedArrayType& node) { this->process(node); } void NullVisitor::visit(RecordType& node) { this->process(node); } void NullVisitor::visit(RecordTypeElement& node) { this->process(node); } void NullVisitor::visit(Aggregate& node) { this->process(node); } void NullVisitor::visit(SubtypeIndication& node) { this->process(node); } void NullVisitor::visit(Library& node) { this->process(node); } void NullVisitor::visit(Subscript& node) { this->process(node); } void NullVisitor::visit(Slice &node) { this->process(node); } void NullVisitor::visit(ConstInteger &node) { this->process(node); } void NullVisitor::visit(TypeConversion &node) { this->process(node); } void NullVisitor::visit(AttributeDeclaration &node) { this->process(node); } void NullVisitor::visit(AttributeSpecification &node) { this->process(node); } void NullVisitor::process(ValDeclaration &node) { SymbolDeclaration& sNode = static_cast(node); this->process(sNode); } void NullVisitor::process(SymbolDeclaration &node) { AstNode& aNode = static_cast(node); this->process(aNode); } void NullVisitor::process(Expression &node) { AstNode& aNode = static_cast(node); this->process(aNode); } void NullVisitor::process(SeqStat &node) { AstNode& anode = static_cast(node); this->process(anode); } void NullVisitor::process(LoopStat &node) { SeqStat& snode = static_cast(node); this->process(snode); } void NullVisitor::process(ConditionedStat &node) { SeqStat& snode = static_cast(node); this->process(snode); } void NullVisitor::process(Callable &node) { SymbolDeclaration& snode = static_cast(node); this->process(snode); } void NullVisitor::process(LibUnit &node) { AttributableDeclaration& snode = static_cast(node); this->process(snode); } void NullVisitor::process(TypeDeclaration &node) { SymbolDeclaration& snode = static_cast(node); this->process(snode); } void NullVisitor::process(PrefixedName &node) { Name &n = static_cast(node); this->process(n); } void NullVisitor::process(Name &node) { Expression& exp = static_cast(node); this->process(exp); } void NullVisitor::process(AttributableDeclaration &node) { SymbolDeclaration &snode = static_cast(node); this->process(snode); } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/GCRegisterSet.hpp0000664000175000017500000001644211502711043021504 0ustar potyrapotyra/* $Id: GCRegisterSet.hpp 5085 2010-12-17 16:38:59Z potyra $ * * RegisterSet defines a means to address signals, drivers, values, and to * apply operations on these. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __GC_REGISTER_SET_HPP_INCLUDED #define __GC_REGISTER_SET_HPP_INCLUDED #include "intermediate/operands/Register.hpp" #include "frontend/ast/Types.hpp" #include "frontend/ast/TypeDeclaration.hpp" #include "intermediate/container/CodeContainer.hpp" #include namespace ast { //! register set used to propagate values from/to expressions class RegisterSet { public: //! c'tor to initialize members with NULL /** This c'tor will do nothing but initializing the members * with NULL. */ RegisterSet( intermediate::CodeContainer &container ) : value(NULL), composite(NULL), sliceBegin(NULL), sliceEnd(NULL), cc(&container), isSignal(false) { } //! copy c'tor, adjust reference counts. RegisterSet( const RegisterSet &other ) : value(other.value), composite(other.composite), sliceBegin(other.sliceBegin), sliceEnd(other.sliceEnd), cc(other.cc), leftBounds(other.leftBounds), rightBounds(other.rightBounds), directions(other.directions), isSignal(other.isSignal) {} //! d'tor, free references. ~RegisterSet() { util::MiscUtil::terminate(this->value); util::MiscUtil::terminate(this->composite); util::MiscUtil::terminate(this->sliceBegin); util::MiscUtil::terminate(this->sliceEnd); } //! assignment operator /** @param other RegisterSet to assign to this RegisterSet. * @return nothing, chained assignment is ugly and should be * avoided. */ RegisterSet * operator =(const RegisterSet &other) { util::MiscUtil::terminate(this->value); util::MiscUtil::terminate(this->composite); util::MiscUtil::terminate(this->sliceBegin); util::MiscUtil::terminate(this->sliceEnd); if (other.value != NULL) { this->value = other.value; } if (other.composite != NULL) { this->composite = other.composite; } if (other.sliceBegin != NULL) { this->sliceBegin = other.sliceBegin; } if (other.sliceEnd != NULL) { this->sliceEnd = other.sliceEnd; } this->isSignal = other.isSignal; this->cc = other.cc; this->leftBounds = other.leftBounds; this->rightBounds = other.rightBounds; this->directions = other.directions; return this; } //! retrieve an Operand containing the real/integer value. /** @param bt base type. * @return operand with an integral or real value. Reference count * is already increased. */ intermediate::Operand *getValue(enum BaseType bt); /** retrieve an Operand with which a variable or Signal can be * modified. For a variable, this will be an indirect operand. * For a signal or driver, it will be a pointer to the signal * or driver instance, which can be passed as is to update, connect, * or getsig. * * value (immediate) -> error * variable: -> IndirectOperand(pointer to data instance) * signal: -> pointer to signal instance. * driver: -> error * * @param bt base type. * @return operand which can be used in an Update or Mov Opcode to * update the signal or respectively the variable. * Reference count is already increased. */ intermediate::Operand *getDestination(enum BaseType bt); /** retrieve a pointer to the storage location. * This method is useful to perform offset calculations, which need * to be based on pointers. * Since the intermediate only has handles to pointers of signals and * drivers, which will be created during run-time - out of scope of * the intermediate code - arrays or records are stored as arrays * of pointers to actual signals. getPointer will contain the pointer * to the elements in a composite type, so that aoffset/roffset can * add offsets to that pointers which in turn must be dereferenced to * obtain the pointer to the signal or driver. * * value (immediate) -> error * variable -> pointer to variable. * signal -> pointer to pointer to signal instance. * driver -> pointer to pointer to driver instance. * * @return pointer to storage location. */ intermediate::Operand *getPointer(void); /** set the pointer to the storage location. * value (immediate) -> error * variable -> pointer to variable * signal -> pointer to pointer to signal * driver -> pointer to pointer to driver * * @param ptr Operand with above semantics. */ void setPointer(intermediate::Operand *ptr); /** set the value. * value (immediate) -> value * variable (indirect) -> value (or error?) * signal -> error * driver -> error */ void setValue(intermediate::Operand *val); /** treat RegisterSet contents as an array, and subscribe to it * with the indices. * @param arrayType array type that the array should refer to. * @param indices list of relative indices of the array. */ void subscribe( TypeDeclaration *arrayType, std::list indices); /** denote, that the current content refers to an unconstraint * array, and has the lower/upper bounds and directions. * @param lb left bounds of the unconstraint array. * @param rb right bounds of the unconstraint array. * @param ds directions of the unconstraint array. */ void setUnconstraintBounds( std::list lb, std::list rb, std::list ds); /** does the RegisterSet refer to an unconstraint array? */ bool isUnconstraint(void) const; /** store the current applicable lower/upper bounds and the * directions of an unconstraint array in lb/ub/ds. * @param lb: list to store lower bounds in. * @param rb: list to store upper bounds in. * @param ds: list to store directions in. */ void getConstraints( std::list &lb, std::list &rb, std::list &ds) const; private: /** operand that contains an integer/real value. Don't read this * operand directly, use getValue() instead. */ intermediate::Operand *value; /** Operand referring to the (base) address of a composite type, * or to the address of a variable, signal or driver. * To obtain the value, use getValue(). */ intermediate::Operand *composite; public: /* FIXME should be private as well */ //! register containing the low bound of a slice (integer) /** currently ignored in almost all cases FIXME */ intermediate::Operand *sliceBegin; //! register containing the high bound of a slice (integer) /** currently ignored in almost all cases FIXME */ intermediate::Operand *sliceEnd; private: //! current code container. intermediate::CodeContainer *cc; //! left bounds of an unconstraint array. std::list leftBounds; //! right bounds of an unconstraint array. std::list rightBounds; //! directions of an unconstraint array. std::list directions; public: //! does the composite value refer to a signal/driver? bool isSignal; }; }; /* namespace ast */ #endif /* __GC_REGISTER_SET_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/TopDownVisitor.hpp0000664000175000017500000002770011243477217022021 0ustar potyrapotyra/* $Id: TopDownVisitor.hpp 4555 2009-08-21 11:01:35Z potyra $ * TopDownVisitor: Base class of Visitors that need a standard (top-down) * traversal. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TOP_DOWN_VISITOR_HPP_INCLUDED #define __TOP_DOWN_VISITOR_HPP_INCLUDED #include "frontend/visitor/Visitor.hpp" namespace ast { //! Visits all nodes top down. /** This class visits all nodes in top down order. */ class TopDownVisitor : public Visitor { public: /** c'tor */ TopDownVisitor(); /** dummy d'tor */ virtual ~TopDownVisitor() {} /** visit a ElementAssociation * @param node node that get's visited. */ virtual void visit(ElementAssociation &node); /** visit a ConstInteger * @param node node that get's visited. */ virtual void visit(ConstInteger &node); /** visit a ConstReal * @param node node that get's visited. */ virtual void visit(ConstReal &node); /** visit a ConstArray * @param node node that get's visited. */ virtual void visit(ConstArray &node); /** Visit an Entity declaration. * @param node Entity Declaration node that get's visited. */ virtual void visit(Entity &node); /** Visit an Signal declaration. * @param node SignalDeclaration node that get's visited. */ virtual void visit(SignalDeclaration &node); /** Visit an Constant declaration. * @param node ConstantDeclaration node that get's visited. */ virtual void visit(ConstantDeclaration &node); /** Visit a FunctionCall. * @param node FunctionCall node that get's visited. */ virtual void visit(FunctionCall &node); /** Visit an IfStat. * @param node IfStat node that get's visited. */ virtual void visit(IfStat &node); /** Visit a NullStat. * @param node IfStat node that get's visited. */ virtual void visit(NullStat &node); /** Visit a ForLoopStat * @param node ForLoopStat node that get's visited. */ virtual void visit(ForLoopStat &node); /** Visit a WhileLoopStat * @param node WhileLoopStat node that get's visited. */ virtual void visit(WhileLoopStat &node); /** Visit a NextStat * @param node NextStat node that get's visited. */ virtual void visit(NextStat &node); /** Visit a VarAssignStat * @param node VarAssignStat node that get's visited. */ virtual void visit(VarAssignStat &node); /** Visit a WaitStat * @param node WaitStat node that get's visited. */ virtual void visit(WaitStat &node); /** Visit a ExitStat * @param node ExitStat node that get's visited. */ virtual void visit(ExitStat &node); /** Visit a SigAssignStat * @param node SigAssignStat node that get's visited. */ virtual void visit(SigAssignStat &node); /** Visit a WaveFormElem * @param node WaveFormElem node that get's visited. */ virtual void visit(WaveFormElem &node); /** Visit a ReturnStat * @param node ReturnStat node that get's visited. */ virtual void visit(ReturnStat &node); /** Visit a ProcCallStat * @param node ReturnStat node that get's visited. */ virtual void visit(ProcCallStat &node); /** Visit an AssertStat * @param node AssertStat node that get's visited. */ virtual void visit(AssertStat &node); /** Visit a VarDeclaration * @param node VarDeclaration node that get's visited. */ virtual void visit(VarDeclaration &node); /** Visit a DiscreteRange * @param node DiscreteRange node that get's visited. */ virtual void visit(DiscreteRange &node); /** Visit a CaseStat * @param node CaseStat node that get's visited. */ virtual void visit(CaseStat &node); /** Visit a CaseAlternative * @param node CaseAlternative node that get's visited. */ virtual void visit(CaseAlternative &node); /** Visit a Others node. * @param node Others node that get's visited. */ virtual void visit(Others &node); /** Visit an Architecture node. * @param node Architecture node that get's visited. */ virtual void visit(Architecture &node); /** Visit a AssociationElement node. * @param node AssociationElement node that get's visited. */ virtual void visit(AssociationElement &node); /** Visit a FunctionDeclaration node. * @param node FunctionDeclaration node that get's visited. */ virtual void visit(FunctionDeclaration &node); /** Visit a ProcedureDeclaration node. * @param node ProcedureDeclaration node that get's visited. */ virtual void visit(ProcedureDeclaration &node); /** Visit a CompInstStat node. * @param node CompInstStat node that get's visited. */ virtual void visit(CompInstStat &node); /** Visit a Package node. * @param node Package node that get's visited. */ virtual void visit(Package &node); /** Visit a PackageBody node. * @param node PackageBody node that get's visited. */ virtual void visit(PackageBody &node); /** Visit a Process node. * @param node Process node that get's visited. */ virtual void visit(Process &node); /** Visit a SubprogBody node. * @param node SubprogBody node that get's visited. */ virtual void visit(SubprogBody &node); /** Visit a CondalSigAssign node. * @param node CondalSigAssign node that get's visited. */ virtual void visit(CondalSigAssign &node); /** Visit an EnumerationType node. * @param node EnumerationType node that get's visited. */ virtual void visit(EnumerationType &node); /** Visit an PhysicalType node. * @param node PhysicalType node that get's visited. */ virtual void visit(PhysicalType &node); /** Visit an PhysicalTypeUnit node. * @param node PhysicalTypeUnit node that get's visited. */ virtual void visit(PhysicalTypeUnit &node); /** Visit an RangeConstraintType node. * @param node RangeConstraintType node that get's visited. */ virtual void visit(RangeConstraintType &node); /** Visit an UnconstrainedArrayType node. * @param node UnconstrainedArrayType node that get's visited. */ virtual void visit(UnconstrainedArrayType &node); /** Visit an RecordType node. * @param node RecordType node that get's visited. */ virtual void visit(RecordType &node); /** Visit an RecordTypeElement node. * @param node RecordTypeElement node that get's visited. */ virtual void visit(RecordTypeElement &node); /** Visit an Aggregate node. * @param node Aggregate node that get's visited. */ virtual void visit(Aggregate &node); /** Visit a SubtypeIndication node. * @param node SubtypeIndication node that get's visited. */ virtual void visit(SubtypeIndication &node); /** Visit a Library node. * @param node Library node that get's visited. */ virtual void visit(Library &node); /** Visit a LibraryList node. * @param node LibraryList node that get's visited. */ virtual void visit(LibraryList &node); /** Visit a Subscript node. * @param node Subscript node that get's visited. */ virtual void visit(Subscript &node); /** Visit a Slice node. * @param node Slice node that get's visited. */ virtual void visit(Slice &node); /** Visit a TypeConversion node. * @param node TypeConversion node that get's visited. */ virtual void visit(TypeConversion &node); /** visit a SimpleName * @param node node that get's visited. */ virtual void visit(SimpleName &node); /** visit a TemporaryName * @param node node that get's visited. */ virtual void visit(TemporaryName &node); /** visit a SelectedName * @param node node that get's visited. */ virtual void visit(SelectedName &node); /** visit a AttributeName * @param node node that get's visited. */ virtual void visit(AttributeName &node); /** Visit an AttributeDeclaration node. * @param node AttributeDeclaration node that gets visited. */ virtual void visit(AttributeDeclaration &node); /** Visit an AttributeSpecification node. * @param node AttributeSpecification node that gets visited. */ virtual void visit(AttributeSpecification &node); protected: //! Process a generic AstNode. /** This function will get called for each AstNode * that get's visited. * * @param node AstNode */ virtual void process(AstNode &node); //! Process a generic ValDeclaration. /** This function will get called for each ValDeclaration (or class * derived from ValDeclaration) that get's visited. * * @param node ValDeclaration instance. */ virtual void process(ValDeclaration &node); //! Process a generic SymbolDeclaration. /** This function will get called for each SymbolDeclaration (or class * derived from SymbolDeclaration) that get's visited. * * @param node SymbolDeclaration instance. */ virtual void process(SymbolDeclaration &node); //! Process a generic Expression. /** This function will get called for each Expression (or class * derived from Expression) that get's visited. * * @param node Expression instance. */ virtual void process(Expression &node); //! Process a generic SeqStat. /** This function will get called for each SeqStat (or class * derived from SeqStat) that get's visited. * * @param node SeqStat instance. */ virtual void process(SeqStat &node); //! Process a generic LoopStat. /** This function will get called for each LoopStat (or class * derived from LoopStat) that get's visited. * * @param node LoopStat instance. */ virtual void process(LoopStat &node); //! Process a generic ConditionedStat. /** This function will get called for each ConditionedStat (or class * derived from ConditionedStat) that get's visited. * * @param node ConditionedStat instance. */ virtual void process(ConditionedStat &node); //! Process a generic Callable. /** This function will get called for each Callable (or class * derived from Callable) that get's visited. * * @param node Callable instance. */ virtual void process(Callable &node); //! Process a generic LibUnit. /** This function will get called for each LibUnit (or class * derived from LibUnit) that get's visited. * * @param node LibUnit instance. */ virtual void process(LibUnit &node); //! Process a generic TypeDeclaration. /** This function will get called for each TypeDeclaration (or class * derived from TypeDeclaration) that get's visited. * * @param node TypeDeclaration instance. */ virtual void process(TypeDeclaration& node); //! Process a generic PrefixedName. /** This function will get called for each PrefixedName (or class * derived from PrefixedName) that get's visited. * * @param node PrefixedName instance. */ virtual void process(PrefixedName &node); //! Process a generic Name. /** This function will get called for each Name (or class * derived from Name) that get's visited. * * @param node Name instance. */ virtual void process(Name &node); //! Process a AttributableDeclaration. /** This function will get called for each AttributableDeclaration * (or class derived from it) that gets visited. * * @param node AttributableDeclaration instance. */ virtual void process(AttributableDeclaration &node); /** debug: how many times has a visitor been created? * this value should always be >= astnode.numVisits, otherwise * there is an endless recursion somewhere. * In case a visitor is run more than once, make sure to increase * visits every time. */ static int visits; }; }; /* namespace ast */ #endif /* __TOP_DOWN_VISITOR_HPP_INCLUDED */ fauhdlc-20130704/frontend/visitor/GCBuiltins.cpp0000664000175000017500000001760511173331610021034 0ustar potyrapotyra/* $Id: GCBuiltins.cpp 4489 2009-04-21 11:52:40Z potyra $ * * Generate intermediate code, intermediate code implementation of builtins. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/GCBuiltins.hpp" #include #include "frontend/ast/AssociationElement.hpp" #include "frontend/misc/BuiltinSymbolTable.hpp" #include "intermediate/container/LabelFactory.hpp" #include "intermediate/operands/ImmediateOperand.hpp" #include "intermediate/opcodes/Mov.hpp" #include "intermediate/opcodes/Je.hpp" #include "intermediate/opcodes/Jne.hpp" #include "intermediate/opcodes/Jb.hpp" #include "intermediate/opcodes/Jbe.hpp" namespace ast { using namespace intermediate; RegisterSet GCBuiltinsNoShortCircuit::emitCode( GenCode &gc, std::list ops ) const { std::list cOps; std::list btls; for (std::list::iterator i = ops.begin(); i != ops.end(); i++) { GenCode lgc = GenCode(gc.container); assert((*i)->formal == NULL); // FIXME assert((*i)->actual != NULL); (*i)->actual->accept(lgc); cOps.push_back(lgc.sourceRegs); btls.push_back((*i)->actual->baseType); } return this->calculate(*gc.container, cOps, btls); } RegisterSet GCBuiltinsShortCircuit::emitCode( GenCode &gc, std::list ops ) const { // FIXME this doesn't work for composite types, e.g. bit-vectors. assert(ops.size() == 2); std::list::iterator i = ops.begin(); Label *out = LabelFactory::getLabel("builtin_shortcut_result"); // result = Register *result = gc.container->createRegister(OP_TYPE_INTEGER); Mov *def = new Mov(new ImmediateOperand(this->getDefault()), result); gc.container->addCode(def); // leftop = (..) Operand *leftOp = this->evaluate(gc.container, **i); i++; // if leftop == goto out Je *shortCut = new Je(leftOp, new ImmediateOperand(this->getShortCut()), out); gc.container->addCode(shortCut); // rightop = (..) Operand *rightOp = this->evaluate(gc.container, **i); // if rightop == goto out Je *shortCut2 = new Je(rightOp, new ImmediateOperand(this->getShortCut()), out); gc.container->addCode(shortCut2); // result = 1 - Mov *altRes = new Mov(new ImmediateOperand(1 - this->getDefault()), result); gc.container->addCode(altRes); // out: gc.container->addCode(out); RegisterSet ret = RegisterSet(*gc.container); ret.setValue(result); return ret; } Operand * GCBuiltinsShortCircuit::evaluate( CodeContainer *cc, AssociationElement &assoc ) { GenCode gc = GenCode(cc); // FIXME composites assert(assoc.formal == NULL); assert(assoc.actual != NULL); assoc.actual->accept(gc); Operand *ret = gc.sourceRegs.getValue(assoc.actual->baseType); assert(ret != NULL); return ret; } RegisterSet GCBuiltinsUnop::calculate( CodeContainer &cc, std::list ops, std::list btl ) const { assert(ops.size() == 1); RegisterSet r = *ops.begin(); Operand *value = r.getValue(btl.front()); Register *result = this->calcUnOp(cc, value); RegisterSet rset = RegisterSet(cc); rset.setValue(result); return rset; } RegisterSet GCBuiltinsBinOp::calculate( CodeContainer &cc, std::list ops, std::list btl ) const { assert(ops.size() == 2); std::list::const_iterator i = ops.begin(); std::list::const_iterator j = btl.begin(); RegisterSet left = *i; enum BaseType leftBT = *j; i++; j++; RegisterSet right = *i; enum BaseType rightBT = *j; Operand *leftOp = left.getValue(leftBT); Operand *rightOp = right.getValue(rightBT); assert(leftOp != NULL); assert(rightOp != NULL); Register *result = this->calcBinOp(cc, leftOp, rightOp); RegisterSet rset = RegisterSet(cc); rset.setValue(result); return rset; } /* ********************** implementation of builtins ******************* */ Register * GCBuiltinsNot::calcUnOp(CodeContainer &cc, Operand *op) const { // not for bit, boolean: 1 - op // (which is only valid if '1'/true == 1 and '0'/false == 0) assert(VHDL_TRUE == 1); assert(VHDL_FALSE == 0); Register *result = cc.createRegister(OP_TYPE_INTEGER); Sub *sub = new Sub(ImmediateOperand::getOne(), op, result); cc.addCode(sub); return result; } Register * GCBuiltinsXor::calcBinOp( CodeContainer &cc, Operand *left, Operand *right ) const { //t = left + right. //Xor = t == 2 ? 0 : t; Register *lsumr = cc.createRegister(OP_TYPE_INTEGER); Add *add = new Add(left, right, lsumr); cc.addCode(add); ImmediateOperand *two = new ImmediateOperand(static_cast(2)); Label *out = LabelFactory::getLabel("xor_out"); Jb *jb = new Jb(lsumr, two, out); cc.addCode(jb); Mov *mov = new Mov(ImmediateOperand::getZero(), lsumr); cc.addCode(mov); cc.addCode(out); return lsumr; } Register * GCBuiltinsXnor::calcBinOp( CodeContainer &cc, Operand *left, Operand *right ) const { //xnor : not xor -> 1 - xor(left, right) Register *ret = GCBuiltinsXor::calcBinOp(cc, left, right); Register *res = cc.createRegister(OP_TYPE_INTEGER); Sub *sub = new Sub(ImmediateOperand::getOne(), ret, res); cc.addCode(sub); return res; } Register * GCBuiltinsCompare::calcBinOp( CodeContainer &cc, Operand *left, Operand *right ) const { Register *result = cc.createRegister(OP_TYPE_INTEGER); ImmediateOperand *default_op = new ImmediateOperand(this->getDefaultValue()); Mov *mov = new Mov(default_op, result); cc.addCode(mov); Label *out = LabelFactory::getLabel("compare_out"); OpCode *branch = this->emitBranch(left, right, out); cc.addCode(branch); ImmediateOperand *non_default_op = new ImmediateOperand(1 - this->getDefaultValue()); Mov *mov2 = new Mov(non_default_op, result); cc.addCode(mov2); cc.addCode(out); return result; } OpCode * GCBuiltinsEqual::emitBranch(Operand *left, Operand *right, Label *out) const { return new Je(left, right, out); } OpCode * GCBuiltinsInEqual::emitBranch(Operand *left, Operand *right, Label *out) const { return new Jne(left, right, out); } OpCode * GCBuiltinsLess::emitBranch(Operand *left, Operand *right, Label *out) const { return new Jb(left, right, out); } OpCode * GCBuiltinsLessEqual::emitBranch( Operand *left, Operand *right, Label *out ) const { return new Jbe(left, right, out); } OpCode * GCBuiltinsGreater::emitBranch( Operand *left, Operand *right, Label *out ) const { return new Jbe(left, right, out); } OpCode * GCBuiltinsGreaterEqual::emitBranch( Operand *left, Operand *right, Label *out ) const { return new Jb(left, right, out); } Register * GCBuiltinsUnaryMinus::calcUnOp(CodeContainer &cc, Operand *op) const { // unary minus: 0 - Register *result = cc.createRegister(op->type); Sub *sub = new Sub(ImmediateOperand::getZero(), op, result); cc.addCode(sub); return result; } RegisterSet GCBuiltinsIdentity::emitCode( GenCode &gc, std::list ops ) const { assert(ops.size() == 1); AssociationElement *elem = ops.front(); assert(elem->formal == NULL); assert(elem->actual != NULL); GenCode lgc = GenCode(gc.container); elem->actual->accept(lgc); // just pass on the RegisterSet of the argument. return lgc.sourceRegs; } Register * GCBuiltinsAbs::calcUnOp(CodeContainer &cc, Operand *op) const { // res = op // if 0 < res goto out // res = 1 - res // out: // Register *result = cc.createRegister(op->type); Mov *ir = new Mov(op, result); cc.addCode(ir); Label *absOut = LabelFactory::getLabel("abs_out"); Jb *goOut = new Jb(ImmediateOperand::getZero(), op, absOut); cc.addCode(goOut); Sub *invert = new Sub(ImmediateOperand::getZero(), op, result); cc.addCode(invert); cc.addCode(absOut); return result; } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/Visitor.tpp0000664000175000017500000000310611266060117020504 0ustar potyrapotyra/* $Id: Visitor.tpp 4822 2009-10-16 12:00:15Z potyra $ * vim:tabstop=8:shiftwidth=8:filetype=cpp:textwidth=72: * Visitor: base class for all visitors. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include namespace ast { template void Visitor::listTraverse(const T &l) { for (typename T::const_iterator i = l.begin(); i != l.end(); i++) { assert(*i); (*i)->accept(*this); } } template void Visitor::listTraverse(T &l, bool &deleteFlag) { typename T::iterator i=l.begin(); while (i != l.end()) { assert(*i); (*i)->accept(*this); if (deleteFlag) { i = l.erase(i); deleteFlag = false; continue; } i++; } } template void Visitor::listTraverse(T &l, bool &replaceFlag, T &replace) { typename T::iterator i=l.begin(); while (i != l.end()) { assert(*i); (*i)->accept(*this); if (replaceFlag) { i = l.erase(i); l.insert(i, replace.begin(), replace.end()); replace.clear(); replaceFlag = false; continue; } i++; } } template void Visitor::listTraverse(T &l, T &insert) { for (typename T::iterator i = l.begin(); i != l.end(); i++) { assert(*i); (*i)->accept(*this); if (! insert.empty()) { l.insert(i, insert.begin(), insert.end()); insert.clear(); } } } }; /* namespace ast */ fauhdlc-20130704/frontend/visitor/CheckLoops.cpp0000664000175000017500000000412311137610234021054 0ustar potyrapotyra/* $Id: CheckLoops.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Check, if next statements occur within a loop statement. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/visitor/CheckLoops.hpp" #include "frontend/ast/LoopStat.hpp" #include "frontend/ast/NextStat.hpp" #include "frontend/ast/ExitStat.hpp" #include "frontend/reporting/ErrorRegistry.hpp" namespace ast { template void CheckLoops::visitLoopCFNode(T &node, const char *kind) const { LoopStat *referred = this->lookup(node.loopLabel); if (referred == NULL) { this->missingLoop(node, node.loopLabel, kind); return; } assert(node.referredLoop == NULL); node.referredLoop = referred; } void CheckLoops::visit(ExitStat &node) { this->visitLoopCFNode(node, "Exit"); } void CheckLoops::visit(NextStat &node) { this->visitLoopCFNode(node, "Next"); } void CheckLoops::process(LoopStat &node) { this->loops.push_front(&node); assert(node.loopStats != NULL); if (node.loopStats->empty()) { // issue warning? } this->listTraverse(*node.loopStats); this->loops.pop_front(); } LoopStat * CheckLoops::lookup(SimpleName *label) const { if (label == NULL) { if (this->loops.empty()) { return NULL; } return this->loops.front(); } for (std::list::const_iterator i = this->loops.begin(); i != this->loops.end(); i++) { if (((*i)->name != NULL) && (*(*i)->name == *label->name)) { return *i; } } return NULL; } void CheckLoops::missingLoop( const AstNode &node, const SimpleName *label, const char *kind ) const { std::string msg; if (label == NULL) { msg = kind; msg += " statement not within a loop statement."; } else { assert(label->name != NULL); msg = "Missing loop statement with label <" + *label->name + ">."; } CompileError *ce = new CompileError(node, msg); ErrorRegistry::addError(ce); } }; /* namespace ast */ fauhdlc-20130704/frontend/newparser/0000775000175000017500000000000012165333075016634 5ustar potyrapotyrafauhdlc-20130704/frontend/newparser/gen_parser_gen.py0000775000175000017500000000375511155203660022173 0ustar potyrapotyra#!/usr/bin/env python # $Id: gen_parser_gen.py 4372 2009-03-09 12:12:32Z potyra $ # Copyright (C) 2009 FAUmachine Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. import subprocess import sys def check_bison_version(): output = subprocess.Popen(["bison", "--version"], stdout=subprocess.PIPE).communicate()[0] bv = output.split(")")[1].split("\n")[0].strip() return bv def version_lt(v1, v2): """ v1 < v2 -> True, False otherwise """ v1ses = v1.split(".") v2ses = v2.split(".") v1ses.reverse() v2ses.reverse() while (len(v1ses) > 0) and (len(v2ses) > 0): t1 = v1ses.pop() t2 = v2ses.pop() i1 = int(t1) i2 = int(t2) if (i1 < i2): return True if (i1 > i2): return False # all consumed numbers equal if (len(v1ses) == 0) and (len(v2ses) == 0): return False # either v1 or v2 still contains digits if len(v1ses) > 0: # e.g. "1.2.3.4" vs "1.2.3" return False # v1 empty, but v2 contains digits return True def gen_parser(infile, outfile, version): f = file(infile, "r") of = file(outfile, "w") txt = f.read() f.close() if version_lt(version, "2.4.1"): # use %{ and %} for header code HEADER_DEFINITIONS_START="%{" HEADER_DEFINITIONS_END="%}" else: # 2.4.1 or later, can use "%code requires" HEADER_DEFINITIONS_START="%code requires {" HEADER_DEFINITIONS_END="}" txt = txt.replace("@HEADER_DEFINITIONS_START@", HEADER_DEFINITIONS_START) txt = txt.replace("@HEADER_DEFINITIONS_END@", HEADER_DEFINITIONS_END) of.write(txt) of.close() def usage(): print "%s " % sys.argv[0] if __name__ == '__main__': if len(sys.argv) != 3: usage() sys.exit(1) v = check_bison_version() print "Detect bison version %s" % v print "Generating parser file %s from %s" % (sys.argv[2], sys.argv[1]) gen_parser(sys.argv[1], sys.argv[2], v) fauhdlc-20130704/frontend/newparser/ParserDriver.hpp0000664000175000017500000002252011147530601021747 0ustar potyrapotyra/* $Id: ParserDriver.hpp 4366 2009-02-20 13:34:57Z potyra $ * * ParserDriver: glue class to driver between scanner and parser. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PARSER_DRIVER_HPP_INCLUDED #define __PARSER_DRIVER_HPP_INCLUDED /* attention, this file get's included in several nasty places: 1) at the beginning of the generated scanner. Thus some glue definitions to make it work. 2) From the code-file of the parser */ #include #include #include #include "FAUhdlParser.tab.hh" #include "location.hh" #include "frontend/ast/LibraryList.hpp" #include "frontend/ast/Location.hpp" #include "frontend/reporting/SyntaxError.hpp" #include "frontend/misc/SymbolTable.hpp" #include "frontend/misc/NameLookup.hpp" #include "frontend/reporting/SyntaxError.hpp" #include "frontend/reporting/CompileError.hpp" namespace yy { class ParserDriver; class Identifier; }; /* Announce to Flex the prototype we want for lexing function, ... */ #define YY_DECL \ yy::FAUhdlParser::token_type \ yy::FAUhdlScanner::yylex(yy::FAUhdlParser::semantic_type* yylval, \ yy::FAUhdlParser::location_type* yylloc, \ ParserDriver& driver) /* redefine yyterminate, to be of the same type */ #define yyterminate() return token::t_EOF namespace ast { class Symbol; }; namespace yy { class FAUhdlScanner; /** Glue class, that connects the scanner and the parser. */ class ParserDriver { public: /** c'tor * @param symTab symbol table instance for the scanner. */ ParserDriver(ast::SymbolTable& symTab); /** d'tor */ virtual ~ParserDriver(); /** glue function that will call the real flexer * @param yylval Semantic value of scanned token. * @param yylloc Location of scanned token. */ int yylex( yy::FAUhdlParser::semantic_type* yylval, yy::FAUhdlParser::location_type* yylloc ); //! Report a parse error. /** Used as callback from the parser. * @param l Location of parse errror. * @param msg error message. */ void error( const yy::FAUhdlParser::location_type& l, const std::string& msg ) throw(SyntaxError); /** Parse a file. * @exception runtime_error in case the file could not get opened. * @exception SyntaxError in case there were errors during parsing. * @param filename name of file * @param lib library name the file is in. */ void parse( const std::string& filename, const char *lib ) throw(std::runtime_error, SyntaxError, ast::CompileError); //! Convert a string to lower case. /** The argument will get overwritten with the result. * @param mixed convert this string to lower case */ static void toLower(std::string& mixed); //! Make an float/int from a vhdl based real/int literal. /** can be instantiated with any number type, that can be * static_cast from long. * @param number based vhdl float/int, e.g. 16#FF.1A#E+1 * @return value of the double * @exception std::invalid_argument in case no base specifier * is present. */ template static T makeBased(std::string number) throw(std::invalid_argument); //! Make an float/int from a vhdl unbased real literal. /** can be instantiated with any number type, that can be * static_cast from long. * @param number vhdl float/int, e.g. 123.456E-14 * @return value of the double */ template static T makeBase10(std::string number); //! Remove double quotes from a string. /** will turn "" to ", and also remove the surrounding quotes. * @param s string to mangle. * @return correct string, caller needs to free the allocated mem. */ static std::string* removeQuotes(std::string s); //! Normalize a vhdl bit string. /** Remove surrounding quotes and normalize to binary values. * @param s string that will get normalized. * @return normalized bit string. * @exception if the digit is bigger than allowed. */ static std::string* makeBitString(std::string s) throw(std::out_of_range); //! build an ast::Location. /** build an ast::Location with the given yy::location and the current * file as filename. * * @param loc location in the parser. * @return Location with linenumber and filename. */ ast::Location bl(const location& loc) const { return ast::Location(loc.begin.line, this->currentFile); } //! register given unit to current library. /** register the Library unit unit to the currently opened libary. * @param unit to register */ void registerLibUnit(ast::LibUnit *unit); //! lookup a symbol in the SymbolTable and return the according token. /** wrapper to coordinate between SymbolTable and Scanner. * @param id string of the identifier * @param semanticValue semantic value that will get filled in. * @param loc location of the identifier * @return identifier token type. */ FAUhdlParser::token_type getTokenForId( const char *id, ast::NodeFactory::Identifier *&semanticValue, const FAUhdlParser::location_type &loc) const; //! build the SimpleName of an operator. /** Build the SimpleName of an operator, look it up in the * SymbolTable and complain, if no candidates are found. * * @param op name of the operator. * @param loc location of the operator symbol * @return created SimpleName. */ ast::SimpleName* buildOperatorName( const char *op, const FAUhdlParser::location_type &loc) const; //! register all symbols in symbols with type /** register all symbols named in symbols into the current * region of the symbolTable. * * @param symbols list of symbols to register. * @param type type to register symbols. */ template void registerSymbolDecls( const T *symbols, enum ast::symType type ); /** scanner instance */ FAUhdlScanner *scanner; /** top DesignUnitList */ ast::LibraryList *topNode; /** current library */ ast::Library *currentLibrary; /** symboltable instance for scanner */ ast::SymbolTable &symbolTable; /** glue frontend for SymbolTable while parsing */ ast::NameLookup &nameLookup; /** should identifiers get looked up and reported as individual * ID_* instances? */ bool lookupIdentifiers; /** current label (or NULL) for the sequential/concurrent statement */ std::string *label; /** top will point to the current callable, so that a return statement * can lookup to which it applies. * If empty (i.e. outside of a subprogram), no return statement is * allowed. */ std::stack subprogStack; private: //! Convert an integer string to a long int. /** @param intval sequence of characteres [0-9a-zA-Z], with an * optional prefix of + or -. * @param base base multiplier. * @return value of intval. * @exception invalid_argument intval contains other characters * @exception out_of_range intval characters have greater value * than base */ static long makeLong(const std::string& intval, unsigned char base) throw(std::invalid_argument, std::out_of_range); //! Determine the value of a ascii (extended) digit. /** @param c ascii digit. * @return value of the digit or -1 if out of range. */ static int getDigitValue(char c); //! Normalize a hex bit string. /** @return normalized bit string. Caller must free it. * @param s vhdl hex bit string */ static std::string* makeHexBitString(std::string& s); //! Normalize a octal bit string. /** @return normalized string. Caller must free it. * @param s vhdl octal bit string. * @exception std::out_of_range if a digit is not an octal * digit. */ static std::string* makeOctBitString(std::string& s) throw(std::out_of_range); //! Convert sting number to T. /** @param val value of actual number +-[0-9a-zA-Z] optional with . * @param exponent value of exponent (base 10): [eE]?[+-]?[0-9]* * @param base base multiplier. * @return value of number. * * Note: val and exponent may get modified. */ template static T makeNumberFromParts( std::string& val, std::string& exponent, unsigned char base ); //! reduce candidates to the correct token type. /** reduce the list of candidate symbols candidates to the * corresponding token type for the parser. * @param candidates list of symbol candidates. * @return corresponding token type for candidates. */ static FAUhdlParser::token_type reduceSymbolToToken(std::list candidates); //! report that id could not have been found. /** report an error that the identifier id could not get looked up. * @param id identifier without symbol. * @param loc corresponding location */ void reportNameError( const char *id, const FAUhdlParser::location_type &loc) const; /** name of the current file */ const std::string* currentFile; /** current location of scanner. */ FAUhdlParser::location_type *currentLoc; }; /* class declaration */ }; /* namespace yy */ /* include template definition */ #include "ParserDriver.tpp" #endif /* __PARSER_DRIVER_HPP_INCLUDED */ fauhdlc-20130704/frontend/newparser/Makefile.am0000664000175000017500000000235211155221513020661 0ustar potyrapotyra# $Id: Makefile.am 4379 2009-03-09 14:10:19Z potyra $ AM_CPPFLAGS=-I $(top_srcdir) -I. BUILT_SOURCES=\ FAUhdlParser.tab.cc\ FAUhdlParser.tab.hh\ FAUhdlScanner.cpp\ location.hh\ stack.hh\ position.hh\ FAUhdlParser.yy # generated files, clean these. CLEANFILES=$(BUILT_SOURCES)\ FAUhdlParser.tab.o\ FAUhdlScanner.o noinst_LIBRARIES = libnewparser.a libnewparser_a_SOURCES=\ FAUhdlScanner.cpp\ FAUhdlScanner.hpp\ FAUhdlParser.tab.cc\ FAUhdlParser.tab.hh\ location.hh\ stack.hh\ position.hh\ ParserDriver.cpp libnewparser_a_CXXFLAGS=\ -Wno-conversion \ -Wno-old-style-cast \ -Wno-parentheses EXTRA_DIST = \ FAUhdlParser.yy \ FAUhdlScanner.l # manually add dependencies on created files. FAUhdlParser.tab.hh: FAUhdlParser.tab.cc location.hh: FAUhdlParser.tab.cc stack.hh: FAUhdlParser.tab.cc position.hh: FAUhdlParser.tab.cc # grmpf, bison interface changed incomptabily, need to generate the parser FAUhdlParser.yy: FAUhdlParser.yy.in ./gen_parser_gen.py $< $@ # override rules for flex, automake would make serious foo with it FAUhdlScanner.cpp: FAUhdlScanner.l flex $< # override rules for yacc (i.e. bison), as automake would make # really serious foo with it. FAUhdlParser.tab.cc: FAUhdlParser.yy bison $< .PHONY: devel fauhdlc-20130704/frontend/newparser/FAUhdlScanner.l0000664000175000017500000003611411543660067021436 0ustar potyrapotyra/* $Id: FAUhdlScanner.l 5094 2011-03-27 16:05:11Z potyra $ */ /* vim:tabstop=8:shiftwidth=8:textwidth=72: * VHDL scanner. * * Copyright (C) 2007-2011 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ %option c++ %option outfile="FAUhdlScanner.cpp" %option batch %option case-insensitive %option stack %option noyywrap /* start conditions */ /* the next token starts an association list */ %x ASSOC_LIST /* the token is part of a formal_part */ %s FORMAL /* the token is inside braces in a formal_part */ %s NESTED_FORMAL /* the token is part of an actual part */ %s ACTUAL /* the token is inside braces in an actual_part */ %s ACTUAL_NESTED /* handle tokens in an identifier list followed by a colon. All of these identifieres are declarations. (except specifications, but these can and should be looked up afterwards, since more restrictions apply there) */ %x ID_LIST /* check if the next tokens from an association_list, must be called with yy_push_state. Doesn't consume characters. Sets this->isAssociation as a result and returns to the previous state. */ %x AL_SCANNER /* check if the next token form a formal_part. set state to FORMAL_PART or ACTUAL_PART as result. Doesn't consume characters. */ %x FORMAL_SCANNER %top{ #include #include #include /* ParserDriver.hpp needs to be included before the scanner header */ #include "ParserDriver.hpp" } %{ #include "FAUhdlScanner.hpp" #include "frontend/reporting/ErrorRegistry.hpp" typedef yy::FAUhdlParser::token token; #define DEBUG_SCANNER 0 %} ws [\t\r ] upper [A-Z] lower [a-z] digit [0-9] extended_digit {digit}|[a-fA-F] nl [\n] extupper1 [\0xc0\0xc1\0xc2\0xc3\0xc4\0xc5\0xc6\0xc7\0xc8] extupper2 [\0xc9\0xca\0xcb\0xcd\0xce\0xcf\0xd1\0xd2\0xd2] extupper3 [\0xd4\0xd5\0xd6\0xd8\0xd9\0xda\0xdb\0xdc\0xdd\0xde] extupper {extupper1}|{extupper2}|{extupper3} extlower1 [\0xdf\0xe0\0xe1\0xe2\0xe3\0xe4\0xe5\0xe6\0xe7] extlower2 [\0xe8\0xe9\0xea\0xeb\0xec\0xed\0xee\0xef\0xf0] extlower3 [\0xf1\0xf2\0xf3\0xf4\0xf5\0xf6\0xf8\0xf9\0xfa] extlower4 [\0xfb\0xfc\0xfd\0xfe\0xff] extlower {extlower1}|{extlower2}|{extlower3}|{extlower4} other_special1 [!$%@?\\^`{}~] other_special2 [\0xa1\0xa2\0xa3\0xa4\0xa5\0xa6\0xa7\0xa8\0xa9] other_special3 [\0xaa\0xab\0xac\0xae\0xaf\0xb0\0xb1\0xb2\0xb3\0xb4] other_special4 [\0xb5\0xb6\0xb7\0xb8\0xb9\0xba\0xbb\0xbc\0xbd] other_special5 [\0xbe\0xbf\0xd7\0xf7\0xad] other_specialg1 {other_special1}|{other_special2}|{other_special3} other_specialg2 {other_special4}|{other_special5} other_special {other_specialg1}|{other_specialg2} space_character [ \t] format_effector [\t\v\r\f] special_no_qm [#&'()*+,-/:;<=>\[\]_|] special {special_no_qm}|\" lowercase {lower}|{extlower} uppercase {upper}|{extupper} letter {uppercase}|{lowercase} letter_or_digit {letter}|{digit} basic_id {letter}+(_?{letter_or_digit})* number {digit}(_?{digit})* extended_number {extended_digit}(_?{extended_digit})* pos_exponent [eE]\+?{number} neg_exponent [eE]-{number} exponent {pos_exponent}|{neg_exponent} integer10 {number}({pos_exponent})? real10 {number}\.{number}({exponent})? based_integer {number}\#{extended_number}\#({pos_exponent})? based_real {number}\#{extended_number}\.{extended_number}\#{exponent}? basic_graphic1 {uppercase}|{digit}|{special_no_qm}|{space_character} graphic1 {basic_graphic1}|{lowercase}|{other_special} basic_graphic {uppercase}|{digit}|{special}|{space_character} graphic {basic_graphic}|{lowercase}|{other_special} esc_char \"\" string_seq {graphic1}|{esc_char} char_lit '{graphic}' string_lit \"{string_seq}*\" bit_string [bBoOxX]\"{extended_number}\" %{ /* lookahead expressions for identifier lists followd by a colon. These are always declarations and mustn't get looked up in the symbol table. */ %} comment \-\-[^\v\r\n\f]*[\n] separator {ws}|{format_effector}|{nl}|{comment} id_list ({basic_id}{separator}*\,{separator}*)*{basic_id} ids_with_col {id_list}{separator}*\:[^=] %{ /* lookahead expressions for association_list. Since there cannot exist a regular expression to correctly match an association_list, {association} is a heuristic which must detect all *possible* following association lists, and may detect several non-association-lists as well. It servers the purpose to start the association list parser (modelled as state AL_PARSER) to verify the result. */ %} assoc_part {comment}|{separator}|{string_lit}|{char_lit}|[^;"'] association \({assoc_part}*=>{assoc_part}*; %% { {ws}+ { this->backup += ' '; } {nl} | {comment} { /* ingore comment, only register newline */ this->backup += '\n'; } {char_lit} | {string_lit} | {bit_string} { this->backup += yytext; } \( { this->bracesCtr++; this->backup += '('; } \) { this->bracesCtr--; this->backup += ')'; if (this->bracesCtr <= 0) { this->isAssociation &= (this->bracesCtr == 0); this->putBack(); #if DEBUG_SCANNER if (this->isAssociation) { std::cerr << "association_list <" << this->backup << '>' << std::endl; } #endif yy_pop_state(); } /* nested braces */ } " when " | " is " | \; { this->backup += yytext; this->putBack(); yy_pop_state(); this->isAssociation = false; } "=>" { this->backup += "=>"; if (this->bracesCtr == 1) { this->isAssociation = true; } } . { this->backup += yytext; } } { {ws}+ { this->backup += ' '; } {nl} | {comment} { /* ingore comment, only register newline */ this->backup += '\n'; } {char_lit} | {string_lit} | \| | {bit_string} { this->backup += yytext; } \( { this->bracesCtr++; this->backup += '('; } \) { this->bracesCtr--; this->backup += ')'; if (this->bracesCtr < 0) { this->putBack(); driver.lookupIdentifiers = true; #if DEBUG_SCANNER std::cerr << "not a formal: )" << std::endl; #endif BEGIN(ACTUAL); } /* fall through: nested braces */ } "=>" { this->backup += "=>"; if (this->bracesCtr == 0) { this->putBack(); driver.lookupIdentifiers = false; #if DEBUG_SCANNER std::cerr << "formal_part <" << this->backup << '>' << std::endl; #endif BEGIN(FORMAL); } } \, { this->backup += ','; if (this->bracesCtr == 0) { this->putBack(); driver.lookupIdentifiers = true; #if DEBUG_SCANNER std::cerr << "not a formal: ," << std::endl; #endif BEGIN(ACTUAL); } } . { this->backup += yytext; } } {ws} {} {association} { if (this->scannedForAssociation) { this->scannedForAssociation = false; if (this->isAssociation) { yy_push_state(ASSOC_LIST); yyless(0); } else { REJECT; } } else { #if DEBUG_SCANNER std::cerr << '<' << yytext << '>' << std::endl; std::cerr << "scanning for association_list..." << std::endl; #endif this->reset(); this->scannedForAssociation = true; yy_push_state(AL_SCANNER); yyless(0); } } \( { #if DEBUG_SCANNER std::cerr << "probably a formal_part, scanning..." << std::endl; #endif this->reset(); yy_pop_state(); yy_push_state(FORMAL_SCANNER); return token::t_LeftParen; } \( { #if DEBUG_SCANNER std::cerr << "formal: ( switching to nested formal" << std::endl; #endif yy_push_state(NESTED_FORMAL); #if DEBUG_SCANNER std::cerr << "FORMAl( push" << std::endl; #endif driver.lookupIdentifiers = true; return token::t_LeftParen; } \( { #if DEBUG_SCANNER std::cerr << "NESTED_FORMAl( push" << std::endl; #endif yy_push_state(NESTED_FORMAL); return token::t_LeftParen; } \) { #if DEBUG_SCANNER std::cerr << "NESTED_fORMAL) pop" << std::endl; #endif if (yy_top_state() == FORMAL) { driver.lookupIdentifiers = false; } yy_pop_state(); return token::t_RightParen; } "=>" { #if DEBUG_SCANNER std::cerr << "formal t_Arrow, entering actual" << std::endl; #endif BEGIN(ACTUAL); driver.lookupIdentifiers = true; return token::t_Arrow; } \( { #if DEBUG_SCANNER std::cerr << "ACTUAl( push" << std::endl; #endif yy_push_state(ACTUAL_NESTED); return token::t_LeftParen; } \) { #if DEBUG_SCANNER std::cerr << "actual ). pop." << std::endl; #endif yy_pop_state(); return token::t_RightParen; } \, { #if DEBUG_SCANNER std::cerr << "actual ',' scanning for formal_part." << std::endl; #endif this->reset(); BEGIN(FORMAL_SCANNER); return token::t_Comma; } \( { #if DEBUG_SCANNER std::cerr << "ACTUAL_nESTED( push" << std::endl; #endif yy_push_state(ACTUAL_NESTED); return token::t_LeftParen; } \) { yy_pop_state(); #if DEBUG_SCANNER std::cerr << "ACTUAL_nESTED) pop" << std::endl; #endif return token::t_RightParen; } \& { return token::t_Ampersand; } \' { return token::t_Apostrophe; } \( { #if DEBUG_SCANNER std::cerr << "(" << std::endl; #endif return token::t_LeftParen; } \) { return token::t_RightParen; } "**" { return token::t_DoubleStar; } \* { return token::t_Star; } \+ { return token::t_Plus; } \, { return token::t_Comma; } \- { return token::t_Minus; } ":=" { return token::t_VarAsgn; } \: { return token::t_Colon; } \; { return token::t_Semicolon; } "<=" { return token::t_LESym; } ">=" { return token::t_GESym; } \< { return token::t_LTSym; } \> { return token::t_GTSym; } = { return token::t_EQSym; } \/= { return token::t_NESym; } "=>" { return token::t_Arrow; } "<>" { return token::t_Box; } \| { return token::t_Bar; } ! { return token::t_Bar; } \. { return token::t_Dot; } \/ { return token::t_Slash; } abs { return token::t_ABS; } access { return token::t_ACCESS; } after { return token::t_AFTER; } alias { return token::t_ALIAS;} all { return token::t_ALL; } and { return token::t_AND; } architecture { return token::t_ARCHITECTURE; } array { return token::t_ARRAY; } assert { return token::t_ASSERT; } attribute { return token::t_ATTRIBUTE; } begin { return token::t_BEGIN; } block { return token::t_BLOCK; } body { return token::t_BODY; } buffer { return token::t_BUFFER; } bus { return token::t_BUS; } case { return token::t_CASE; } component { return token::t_COMPONENT; } configuration { return token::t_CONFIGURATION; } constant { return token::t_CONSTANT; } disconnect { return token::t_DISCONNECT; } downto { return token::t_DOWNTO; } else { return token::t_ELSE; } elsif { return token::t_ELSIF; } end { return token::t_END; } entity { return token::t_ENTITY; } exit { return token::t_EXIT; } file { return token::t_FILE; } for { return token::t_FOR; } function { return token::t_FUNCTION; } generate { return token::t_GENERATE; } generic { return token::t_GENERIC; } group { return token::t_GROUP; } guarded { return token::t_GUARDED; } if { return token::t_IF; } impure { return token::t_IMPURE; } in { return token::t_IN; } inertial { return token::t_INERTIAL; } inout { return token::t_INOUT; } is { return token::t_IS; } label { return token::t_LABEL; } library { return token::t_LIBRARY; } linkage { return token::t_LINKAGE; } literal { return token::t_LITERAL; } loop { return token::t_LOOP; } map { return token::t_MAP; } mod { return token::t_MOD; } nand { return token::t_NAND; } new { return token::t_NEW; } next { return token::t_NEXT; } nor { return token::t_NOR; } not { return token::t_NOT; } null { return token::t_NULL; } of { return token::t_OF; } on { return token::t_ON; } open { return token::t_OPEN; } or { return token::t_OR; } others { return token::t_OTHERS; } out { return token::t_OUT; } package { return token::t_PACKAGE; } port { return token::t_PORT; } postponed { return token::t_POSTPONED; } procedure { return token::t_PROCEDURE; } process { return token::t_PROCESS; } pure { return token::t_PURE; } range { return token::t_RANGE; } record { return token::t_RECORD; } register { return token::t_REGISTER; } reject { return token::t_REJECT; } rem { return token::t_REM; } report { return token::t_REPORT; } return { return token::t_RETURN; } rol { return token::t_ROL; } ror { return token::t_ROR; } select { return token::t_SELECT; } severity { return token::t_SEVERITY; } signal { return token::t_SIGNAL; } sla { return token::t_SLA; } sll { return token::t_SLL; } sra { return token::t_SRA; } srl { return token::t_SRL; } shared { return token::t_SHARED; } subtype { return token::t_SUBTYPE; } then { return token::t_THEN; } to { return token::t_TO; } transport { return token::t_TRANSPORT; } type { return token::t_TYPE; } unaffected { return token::t_UNAFFECTED; } units { return token::t_UNITS; } until { return token::t_UNTIL; } use { return token::t_USE; } variable { return token::t_VARIABLE; } wait { return token::t_WAIT; } when { return token::t_WHEN; } while { return token::t_WHILE; } with { return token::t_WITH; } xnor { return token::t_XNOR; } xor { return token::t_XOR; } {based_real} { yylval->r = ParserDriver::makeBased( std::string(yytext)); return token::t_REAL; } {based_integer} { yylval->i = ParserDriver::makeBased(std::string(yytext)); return token::t_INTEGER; } {real10} { yylval->r = ParserDriver::makeBase10(std::string(yytext)); return token::t_REAL; } {integer10} { yylval->i = ParserDriver::makeBase10(std::string(yytext)); return token::t_INTEGER; } {char_lit} { yylval->s = new std::string(yytext); return token::t_CHAR; } {string_lit} { yylval->s = ParserDriver::removeQuotes(std::string(yytext)); return token::t_STRING; } {bit_string} { yylval->s = ParserDriver::makeBitString(std::string(yytext)); return token::t_STRING; } {ids_with_col} { #if DEBUG_SCANNER std::cerr << "ids_with_col, push" << std::endl; #endif yy_push_state(ID_LIST); driver.lookupIdentifiers = false; /* FIXME use yyless(0); instead of reject! */ REJECT; } {basic_id} { return driver.getTokenForId( yytext, yylval->identifier, *yylloc); } {nl} { /* advance location */ yylloc->lines(); yylloc->step(); } {comment} { /* skip comment */ yylloc->lines(); yylloc->step(); } . { /* final catch all rule, report error */ driver.error(*yylloc, "unrecognized token \"" + std::string(yytext) + "\""); } {ws} {} \, { return token::t_Comma; } {basic_id} { return driver.getTokenForId( yytext, yylval->identifier, *yylloc); } \: { /* return to normal state */ #if DEBUG_SCANNER std::cerr << "id_list: pop" << std::endl; #endif yy_pop_state(); driver.lookupIdentifiers = true; return token::t_Colon; } {nl} { yylloc->lines(); yylloc->step(); } {comment} { /* skip comment */ yylloc->lines(); yylloc->step(); } . { /* start condition id_list wrong! */ assert(false); } %% int yyFlexLexer::yylex(void) { throw std::logic_error("this method should never have been called."); } fauhdlc-20130704/frontend/newparser/FAUhdlParser.yy.in0000664000175000017500000022652511311715737022121 0ustar potyrapotyra/* $Id: FAUhdlParser.yy.in 4916 2009-12-15 14:23:27Z potyra $ * * Main VHDL Parser. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ %skeleton "lalr1.cc" /* -*- C++ -*- */ %require "2.1a" /* need this for c++ skeleton */ %define "parser_class_name" "FAUhdlParser" %defines %error-verbose %parse-param {yy::ParserDriver &driver} /* %lex-param {location_type* yylloc} */ @HEADER_DEFINITIONS_START@ /* this section will be part of the header */ #include #include #include "frontend/ast/Expression.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/WaveFormElem.hpp" #include "frontend/ast/NodeFactory.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/SubprogBody.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/Types.hpp" /* forward declaration of class, we'd end up with circular includes if this was included here already. */ namespace yy { class ParserDriver; }; @HEADER_DEFINITIONS_END@ %token t_EOF 0; %token t_Ampersand; %token t_Apostrophe; %token t_LeftParen; %token t_RightParen; %token t_DoubleStar; %token t_Star; %token t_Plus; %token t_Comma; %token t_Minus; %token t_VarAsgn; %token t_Colon; %token t_Semicolon; %token t_LESym; %token t_GESym; %token t_LTSym; %token t_GTSym; %token t_EQSym; %token t_NESym; %token t_Arrow; %token t_Box; %token t_Bar; %token t_Dot; %token t_Slash; %token t_ABS; %token t_ACCESS; %token t_AFTER; %token t_ALIAS; %token t_ALL; %token t_AND; %token t_ARCHITECTURE; %token t_ARRAY; %token t_ASSERT; %token t_ATTRIBUTE; %token t_BEGIN; %token t_BLOCK; %token t_BODY; %token t_BUFFER; %token t_BUS; %token t_CASE; %token t_COMPONENT; %token t_CONFIGURATION; %token t_CONSTANT; %token t_DISCONNECT; %token t_DOWNTO; %token t_ELSE; %token t_ELSIF; %token t_END; %token t_ENTITY; %token t_EXIT; %token t_FILE; %token t_FOR; %token t_FUNCTION; %token t_GENERATE; %token t_GENERIC; %token t_GROUP; %token t_GUARDED; %token t_IF; %token t_IMPURE; %token t_IN; %token t_INERTIAL; %token t_INOUT; %token t_IS; %token t_LABEL; %token t_LIBRARY; %token t_LINKAGE; %token t_LITERAL; %token t_LOOP; %token t_MAP; %token t_MOD; %token t_NAND; %token t_NEW; %token t_NEXT; %token t_NOR; %token t_NOT; %token t_NULL; %token t_OF; %token t_ON; %token t_OPEN; %token t_OR; %token t_OTHERS; %token t_OUT; %token t_PACKAGE; %token t_PORT; %token t_POSTPONED; %token t_PROCEDURE; %token t_PROCESS; %token t_PURE; %token t_RANGE; %token t_RECORD; %token t_REGISTER; %token t_REJECT; %token t_REM; %token t_REPORT; %token t_RETURN; %token t_ROL; %token t_ROR; %token t_SELECT; %token t_SEVERITY; %token t_SIGNAL; %token t_SLA; %token t_SLL; %token t_SRA; %token t_SRL; %token t_SHARED; %token t_SUBTYPE; %token t_THEN; %token t_TO; %token t_TRANSPORT; %token t_TYPE; %token t_UNAFFECTED; %token t_UNITS; %token t_UNTIL; %token t_USE; %token t_VARIABLE; %token t_WAIT; %token t_WHEN; %token t_WHILE; %token t_WITH; %token t_XNOR; %token t_XOR; %token t_INTEGER; %token t_REAL; %token t_CHAR; %token t_STRING; %token t_Identifier; /* any unresolved identifier */ %token ID_function; %token ID_type; %token ID_procedure; %union { /* terminal token types */ std::string *s; universal_integer i; universal_real r; bool b; /* enumerated types from terminal tokens */ enum ast::DiscreteRange::Direction direction; enum ast::ValDeclaration::ObjClass obj_class; enum ast::SubprogBody::ProgKind prog_kind; enum ast::ValDeclaration::Mode mode; enum ast::NodeFactory::entityClassE entity_class; /* AST nodes */ ast::Aggregate *aggregate; ast::Architecture *architecture; ast::AssociationElement *association_element; ast::Callable *callable; ast::CaseAlternative *case_alternative; ast::ConcurrentStat *concurrent_stat; ast::ConstInteger *const_integer; ast::DiscreteRange *discrete_range; ast::ElementAssociation *element_association; ast::Entity *entity; ast::Expression *expression; ast::FunctionCall *function_call; ast::FunctionDeclaration *function_declaration; ast::LibUnit *library_unit; ast::LoopStat *loop_stat; ast::Name *name; ast::Package *package; ast::PackageBody *package_body; ast::PhysicalTypeUnit *physical_type_unit; ast::Process *process_statement; ast::ReturnStat *return_statement; ast::SeqStat *seq_stat; ast::SimpleName *simple_name; ast::SubtypeIndication *subtype_indication; ast::SymbolDeclaration *symbol_declaration; ast::WaveFormElem *waveform_element; /* lists of AST nodes */ std::list *l_association_element; std::list* l_case_alternative; std::list *l_concurrent_stat; std::list *l_constantdecl; std::list *l_discrete_range; std::list *l_element_association; std::list *l_expression; std::list *l_function_declaration; std::list *l_name; std::list *l_physical_type_unit; std::list *l_record_element; std::list* l_seqstat; std::list *l_signaldecl; std::list *l_simple_name; std::list *l_symboldecl; std::list *l_typedecl; std::list *l_valdecl; std::list *l_waveform_element; /* helper structures found in NodeFactory and other lists */ ast::NodeFactory::Constraint *h_constraint; ast::NodeFactory::ContextItemS *h_context_item; ast::NodeFactory::Identifier *identifier; ast::NodeFactory::IfHelperS *h_if_stat; ast::NodeFactory::TypeDeclHelper *h_type_decl_helper; std::list *l_string; }; %{ /* this section will be part of the c++-code file */ /* now include the definition of ParserDriver */ #include "ParserDriver.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/ConstReal.hpp" #include "frontend/ast/NodeFactory.hpp" #include "frontend/ast/Others.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/VarAssignStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/ProcCallStat.hpp" #include "frontend/ast/CaseStat.hpp" #include "frontend/ast/ForLoopStat.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/NextStat.hpp" #include "frontend/ast/ExitStat.hpp" #include "frontend/ast/NullStat.hpp" #include "frontend/ast/ReturnStat.hpp" #include "frontend/ast/AssertStat.hpp" #include "frontend/ast/WaitStat.hpp" #include "frontend/ast/Process.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/ast/CompInstStat.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/PackageBody.hpp" #include "frontend/ast/Architecture.hpp" #include "frontend/ast/Package.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/ast/TemporaryName.hpp" #include "frontend/ast/Slice.hpp" #include "frontend/ast/Subscript.hpp" #include "frontend/ast/SelectedName.hpp" #include "frontend/ast/AttributeName.hpp" #include "frontend/ast/ElementAssociation.hpp" #include "frontend/ast/TypeConversion.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/reporting/UndefinedSymbol.hpp" #include "frontend/visitor/ResolveSymbols.hpp" #include "frontend/ast/AttributeDeclaration.hpp" /* nasty remap yylex to the driver's yylex */ #define yylex driver.yylex %} /* ----------- terminals -------------- */ %type opt_guarded opt_postponed opt_shared opt_t_bus pure_or_impure %type t_INTEGER %type t_REAL %type designator concurrent_statement_with_label_begin entity_statement_with_label_begin label operator_symbol opt_designator t_CHAR t_STRING %type direction %type entity_class %type mode opt_mode %type element_kind opt_element_kind %type opt_subprogram_kind subprogram_kind /* -------- non-terminals ------------ */ %type aggregate %type architecture_body architecture_body_begin %type association_element function_association_element %type subprogram_body subprogram_body_begin subprogram_specification %type case_statement_alternative %type component_instantiation_statement concurrent_signal_assignment_statement concurrent_statement concurrent_statement_label_mandatory concurrent_statement_label_optional conditional_signal_assignment entity_statement process_statement selected_signal_assignment %type physical_literal_integer %type discrete_range range range_constraint %type element_association named_element_association %type entity_decl_begin entity_declaration %type actual_designator actual_part add_term and_relation_list attribute_name_begin choice condition expression factor literal opt_condition_clause opt_initializer opt_timeout_clause or_relation_list prefix primary relation relation_list_aoxxn shift_expression simple_expression string_literal term type_conversion xnor_relation_list xor_relation_list abstract_literal numeric_literal physical_literal %type character_literal function_call function_call_w_args function_call_wo_args %type enumeration_literal_decl %type design_unit library_unit primary_unit secondary_unit %type iteration_scheme loop_statement_begin %type adding_operator any_selected_name attribute_name formal_designator formal_part function_formal_part function_name function_selected_name indexed_name instantiated_unit multiplying_operator normal_name opt_physical_type_simple_name opt_simple_declaration_name procedure_name procedure_selected_name range_attribute_name relational_operator selected_name shift_operator sign slice_name target type_name type_selected_name %type package_decl_begin package_declaration %type package_body package_body_begin %type primary_unit_definition secondary_unit_declaration %type process_statement_begin %type return_statement %type assertion assertion_statement case_statement conditional_waveforms exit_statement if_statement loop_statement next_statement null_statement procedure_call procedure_call_statement sequential_statement sequential_statement_without_label sequential_statement_with_label seq_stat signal_assign_statement variable_assign_statement wait_statement %type attribute_designator entity_designator entity_tag function_simple_name logical_name opt_label procedure_simple_name simple_name suffix type_simple_name %type element_subtype_definition index_subtype_definition subtype_indication type_mark %type attribute_specification subprogram_declaration subtype_declaration %type waveform_element /* ------- list of non-terminals ----- */ %type actual_parameter_part association_list function_actual_parameter_part function_association_list generic_map_aspect opt_generic_map_aspect opt_port_map_aspect port_map_aspect %type case_statement_alternative_list selected_waveform_list selected_waveforms %type architecture_statement_list architecture_statement_part entity_statement_list entity_statement_part opt_entity_statement_part %type generic_clause generic_interface_element generic_list opt_generic_clause %type discrete_range_list index_constraint %type element_association_list %type choice_list expression_list %type enumeration_literal_list %type opt_sensitivity_clause opt_sensitivity_list selected_name_list sensitivity_list use_clause %type opt_secondary_unit_declaration_list secondary_unit_declaration_list %type element_declaration element_declaration_list %type process_statement_part sequence_of_statements sequential_statement_list subprogram_statement_part %type opt_port_clause port_clause port_interface_element port_list %type entity_designator_list entity_name_list library_clause logical_name_list %type architecture_declarative_part attribute_declaration block_declarative_item block_declarative_item_list constant_declaration entity_declarative_item entity_declarative_item_list entity_declarative_part package_body_declarative_item package_body_declarative_item_list package_body_declarative_part package_declarative_item package_declarative_item_list package_declarative_part process_declarative_part process_declarative_item process_declarative_item_list signal_declaration subprogram_declarative_item subprogram_declarative_item_list subprogram_declarative_part variable_declaration %type index_subtype_definition_list %type formal_func_parameter_list formal_proc_parameter_list func_interface_element opt_formal_func_parameter_list opt_formal_proc_parameter_list proc_interface_element %type waveform waveform_element_list /* -------- helper types ----------- */ %type constraint %type context_item context_item_list %type elsif_list %type array_type_definition constrained_array_definition composite_type_definition enumeration_type_definition full_type_declaration number_type_definition physical_type_definition record_type_definition scalar_type_definition type_declaration type_definition unconstrained_array_definition %type architecture_body_begin_2 entity_decl_begin_2 ID_function ID_procedure ID_type t_Identifier %type identifier_list %% %start design_file; /* --------- design units --------- */ design_file: design_unit_list ; design_unit_list: design_unit { driver.registerLibUnit($1); // region of last lib unit. driver.symbolTable.popRegion(); // region for next unit. driver.symbolTable.pushNewRegion(); } | design_unit_list design_unit { driver.registerLibUnit($2); // region of last unit. driver.symbolTable.popRegion(); // region for next design_unit driver.symbolTable.pushNewRegion(); } ; design_unit: context_item_list library_unit { $$ = $2; $2->libClauses = $1->libClauses; $2->useClauses = $1->useClauses; delete $1; } | library_unit { $$ = $1; } ; context_item_list: context_item { $$ = $1; } | context_item_list context_item { $$ = &ast::NodeFactory::mergeContextItems(*$1, *$2); } ; context_item: library_clause { $$ = new ast::NodeFactory::ContextItemS(); $$->libClauses = $1; $$->useClauses = NULL; driver.nameLookup.registerLibClauses(*$1); } | use_clause { $$ = new ast::NodeFactory::ContextItemS(); $$->useClauses = $1; $$->libClauses = NULL; driver.nameLookup.registerUseClauses(*$1); } ; library_clause: t_LIBRARY { driver.lookupIdentifiers = false; } logical_name_list { driver.lookupIdentifiers = true; } t_Semicolon { $$ = $3; } ; logical_name_list: logical_name { $$ = new std::list(); $$->push_back($1); } | logical_name_list t_Comma logical_name { $$ = $1; $$->push_back($3); } ; logical_name: t_Identifier { $$ = new ast::SimpleName($1->identifier, driver.bl(@1)); delete $1; } ; use_clause: t_USE selected_name_list t_Semicolon { $$ = $2; } ; selected_name_list: any_selected_name { $$ = new std::list(); $$->push_back($1); } | selected_name_list t_Comma any_selected_name { $$ = $1; $$->push_back($3); } ; library_unit: primary_unit { $$ = $1; } | secondary_unit { $$ = $1; } ; primary_unit: entity_declaration { $$ = $1; } | package_declaration { $$ = $1; } /* | configuration_declaration */ ; secondary_unit: architecture_body { $$ = $1; } | package_body { $$ = $1; } ; /* ------------ names ------------- */ identifier_list: t_Identifier { $$ = new std::list(); $$->push_back($1->identifier); delete $1; } | identifier_list t_Comma t_Identifier { $$ = $1; $$->push_back($3->identifier); delete $3; } ; any_selected_name: selected_name { $$ = $1; } | type_selected_name { $$ = $1; } | function_selected_name { $$ = $1; } | procedure_selected_name { $$ = $1; } ; normal_name: simple_name { $$ = $1; } | selected_name { $$ = $1; } | attribute_name { $$ = $1; } | indexed_name { $$ = $1; } | slice_name { $$ = $1; } /* | operator_symbol { $$ = NULL; } */ ; type_name: type_simple_name { $$ = $1; } | type_selected_name { $$ = $1; } ; type_simple_name: ID_type { $$ = new ast::SimpleName($1->identifier, $1->candidates, driver.bl(@1)); } ; slice_name: normal_name t_LeftParen discrete_range t_RightParen { ast::Slice *s = new ast::Slice($1, $3, driver.bl(@1)); $$ = new ast::TemporaryName(s, driver.bl(@1)); // tricky: a slice will still result in an array, just // propagate the candidates. $$->candidates = $1->candidates; } | function_call_w_args t_LeftParen discrete_range t_RightParen { ast::Slice *s = new ast::Slice($1, $3, driver.bl(@1)); $$ = new ast::TemporaryName(s, driver.bl(@1)); assert($1->subprog != NULL); $$->candidates = $1->subprog->candidates; } | function_name t_LeftParen discrete_range t_RightParen { //$1 must be a function call without arguments. ast::FunctionCall *f = new ast::FunctionCall($1, new std::list(), driver.bl(@1)); ast::Slice *s = new ast::Slice(f, $3, driver.bl(@2)); $$ = new ast::TemporaryName(s, driver.bl(@1)); $$->candidates = $1->candidates; } /* procedure_name not considered, that would make no sense */ /* type_name not considered, that would make no sense */ ; indexed_name: normal_name t_LeftParen expression_list t_RightParen { ast::Subscript *s = new ast::Subscript($1, $3, driver.bl(@1)); $$ = new ast::TemporaryName(s, driver.bl(@1)); $$->candidates = ast::NameLookup::shiftSubscriptCands( $1->candidates, driver.bl(@2)); driver.nameLookup.isExpanded = false; } | function_call_w_args t_LeftParen expression_list t_RightParen { ast::Subscript *s = new ast::Subscript($1, $3, driver.bl(@1)); $$ = new ast::TemporaryName(s, driver.bl(@1)); assert($1->subprog != NULL); $$->candidates = ast::NameLookup::shiftSubscriptCands( $1->subprog->candidates, driver.bl(@2)); driver.nameLookup.isExpanded = false; } /* procedure_name not considered, that would make no sense */ /* type_name not considered, that would make no sense */ /* function_call_wo_args ( idx1, idx2, ... ) is already parsed as a function_call from primary. It *might* be an indexed name, instead of a function_call, but that cannot be determined w.o. type analysis. Hence f(x) could either mean "call f with x as parameter" or "call f without parameter and take element x from the return type." */ ; expression_list: expression { $$ = new std::list(); $$->push_back($1); } | expression_list t_Comma expression { $$ = $1; $$->push_back($3); } ; simple_name: t_Identifier { $$ = new ast::SimpleName($1->identifier, $1->candidates, driver.bl(@1)); } ; function_simple_name: ID_function { $$ = new ast::SimpleName($1->identifier, $1->candidates, driver.bl(@1)); } ; procedure_simple_name: ID_procedure { $$ = new ast::SimpleName($1->identifier, $1->candidates, driver.bl(@1)); } ; function_name: function_simple_name { $$ = $1; } | function_selected_name { $$ = $1; } ; procedure_name: procedure_simple_name { $$ = $1; } | procedure_selected_name { $$ = $1; } selected_name: prefix t_Dot suffix { $$ = driver.nameLookup.makeSelectedName( $1, new std::string(*$3->name), $3->candidates, driver.bl(@3)); util::MiscUtil::terminate($3); driver.nameLookup.unshiftScope(); } | function_call_w_args t_Dot { assert($1->subprog); driver.nameLookup.shiftSelectedScope(*$1->subprog); } suffix { $$ = new ast::SelectedName(new std::string(*$4->name), $1, $4->candidates, driver.bl(@2)); util::MiscUtil::terminate($4); driver.nameLookup.unshiftScope(); } ; function_selected_name: prefix t_Dot ID_function { $$ = driver.nameLookup.makeSelectedName( $1, $3->identifier, $3->candidates, driver.bl(@3)); driver.nameLookup.unshiftScope(); } ; procedure_selected_name: prefix t_Dot ID_procedure { $$ = driver.nameLookup.makeSelectedName( $1, $3->identifier, $3->candidates, driver.bl(@3)); driver.nameLookup.unshiftScope(); } ; type_selected_name: prefix t_Dot ID_type { $$ = driver.nameLookup.makeSelectedName( $1, $3->identifier, $3->candidates, driver.bl(@3)); driver.nameLookup.unshiftScope(); } /* function_call_w_args doesn't make sense as prefix */ ; prefix: normal_name { $$ = $1; driver.nameLookup.shiftScope(*$1, false); } | type_name { $$ = $1; driver.nameLookup.shiftScope(*$1, false); } | function_name { $$ = $1; driver.nameLookup.shiftScope(*$1, true); /* FIXME?? */ if (! driver.nameLookup.isExpanded) { $$ = new ast::FunctionCall($1, new std::list(), driver.bl(@1)); } } | procedure_name { $$ = $1; driver.nameLookup.shiftScope(*$1, false); } ; function_call: function_call_wo_args { $$ = $1; } | function_call_w_args { $$ = $1; } /* FIXME this might as well be an indexed name. */ ; function_call_wo_args: function_name { $$ = new ast::FunctionCall($1, new std::list(), driver.bl(@1)); } ; function_call_w_args: function_name t_LeftParen function_actual_parameter_part t_RightParen { $$ = new ast::FunctionCall($1, $3, driver.bl(@1)); } ; function_actual_parameter_part: function_association_list { $$ = $1; } ; actual_parameter_part: /* paramert */ association_list { $$ = $1; } ; suffix: simple_name { $$ = $1; } /* | t_CHAR { //FIXME //$$ = new ast::Name($1, driver.bl(@1)); $$ = NULL; // enumeration element } */ | t_ALL { $$ = new ast::SimpleName("all", driver.bl(@1)); } /* FIXME operator symbol */ ; attribute_name_begin: prefix t_Apostrophe { $$ = $1; /* TODO scopes for attributes? */ driver.nameLookup.unshiftScope(); driver.nameLookup.shiftAttributeScope(); } ; attribute_name: attribute_name_begin simple_name { $$ = new ast::AttributeName(new std::string(*$2->name), $1, $2->candidates, driver.bl(@2)); util::MiscUtil::terminate($2); driver.nameLookup.unshiftScope(); } | function_call_w_args t_Apostrophe simple_name { $$ = new ast::AttributeName(new std::string(*$3->name), $1, $3->candidates, driver.bl(@2)); util::MiscUtil::terminate($3); driver.nameLookup.unshiftScope(); } ; /* FIXME not covered yet: 'REVERSE_RANGE */ range_attribute_name: attribute_name_begin t_RANGE { $$ = new ast::AttributeName(new std::string("range"), $1, std::list(), driver.bl(@2)); driver.nameLookup.unshiftScope(); } | function_call_w_args t_Apostrophe t_RANGE { $$ = new ast::AttributeName(new std::string("range"), $1, std::list(), driver.bl(@2)); driver.nameLookup.unshiftScope(); } ; /* ----------- expressions -------------- */ choice_list: choice { $$ = new std::list(); $$->push_back($1); } | choice_list t_Bar choice { $$ = $1; $$->push_back($3); } ; /* FIXME */ choice: simple_expression { $$ = $1; } | discrete_range { $$ = $1; } /* | element_simple_name { $$ = NULL; } */ | t_OTHERS { $$ = new ast::Others(driver.bl(@1)); } ; expression: relation t_NAND relation { $$ = new ast::FunctionCall( driver.buildOperatorName("nand", @2), $1, $3, driver.bl(@2)); } | relation t_NOR relation { $$ = new ast::FunctionCall( driver.buildOperatorName("nor", @2), $1, $3, driver.bl(@2)); } | relation_list_aoxxn { $$ = $1; } | relation { $$ = $1; } ; relation_list_aoxxn: and_relation_list { $$ = $1; } | or_relation_list { $$ = $1; } | xor_relation_list { $$ = $1; } | xnor_relation_list { $$ = $1; } ; and_relation_list: relation t_AND relation { $$ = new ast::FunctionCall( driver.buildOperatorName("and", @2), $1, $3, driver.bl(@2)); } | and_relation_list t_AND relation { $$ = new ast::FunctionCall( driver.buildOperatorName("and", @2), $1, $3, driver.bl(@2)); } ; or_relation_list: relation t_OR relation { $$ = new ast::FunctionCall( driver.buildOperatorName("or", @2), $1, $3, driver.bl(@2)); } | or_relation_list t_OR relation { $$ = new ast::FunctionCall( driver.buildOperatorName("or", @2), $1, $3, driver.bl(@2)); } ; xor_relation_list: relation t_XOR relation { $$ = new ast::FunctionCall( driver.buildOperatorName("xor", @2), $1, $3, driver.bl(@2)); } | xor_relation_list t_XOR relation { $$ = new ast::FunctionCall( driver.buildOperatorName("xor", @2), $1, $3, driver.bl(@2)); } ; xnor_relation_list: relation t_XNOR relation { $$ = new ast::FunctionCall( driver.buildOperatorName("xnor", @2), $1, $3, driver.bl(@2)); } | xnor_relation_list t_XNOR relation { $$ = new ast::FunctionCall( driver.buildOperatorName("xnor", @2), $1, $3, driver.bl(@2)); } ; relation: shift_expression { $$ = $1; } | shift_expression relational_operator shift_expression { $$ = new ast::FunctionCall($2, $1, $3, driver.bl(@2)); } ; shift_expression: simple_expression { $$ = $1; } | simple_expression shift_operator simple_expression { $$ = new ast::FunctionCall($2, $1, $3, driver.bl(@2)); } ; simple_expression: sign add_term { $$ = new ast::FunctionCall($1, $2, driver.bl(@1)); } | add_term { $$ = $1; } | term { $$ = $1; } | sign term { $$ = new ast::FunctionCall($1, $2, driver.bl(@1)); } ; add_term: term adding_operator term { $$ = new ast::FunctionCall($2, $1, $3, driver.bl(@2)); } | add_term adding_operator term { $$ = new ast::FunctionCall($2, $1, $3, driver.bl(@2)); } ; term: factor { $$ = $1; } | term multiplying_operator factor { $$ = new ast::FunctionCall($2, $1, $3, driver.bl(@2)); } ; factor: primary { $$ = $1; } | primary t_DoubleStar primary { $$ = new ast::FunctionCall( driver.buildOperatorName("**", @2), $1, $3, driver.bl(@2)); } | t_ABS primary { $$ = new ast::FunctionCall( driver.buildOperatorName("abs", @2), $2, driver.bl(@2)); } | t_NOT primary { $$ = new ast::FunctionCall( driver.buildOperatorName("not", @2), $2, driver.bl(@2)); } ; relational_operator: t_EQSym { $$ = driver.buildOperatorName("=", @1); } | t_EQSym t_EQSym { $$ = driver.buildOperatorName("=", @1); ast::CompileError *ce = new ast::CompileError( driver.bl(@2), "Use '=' instead of '=='."); ast::ErrorRegistry::addError(ce); } | t_NESym { $$ = driver.buildOperatorName("/=", @1); } | t_LTSym { $$ = driver.buildOperatorName("<", @1); } | t_LESym { $$ = driver.buildOperatorName("<=", @1); } | t_GTSym { $$ = driver.buildOperatorName(">", @1); } | t_GESym { $$ = driver.buildOperatorName(">=", @1); } ; shift_operator: t_SLL { $$ = driver.buildOperatorName("sll", @1); } | t_SRL { $$ = driver.buildOperatorName("srl", @1); } | t_SLA { $$ = driver.buildOperatorName("sla", @1); } | t_SRA { $$ = driver.buildOperatorName("sra", @1); } | t_ROL { $$ = driver.buildOperatorName("rol", @1); } | t_ROR { $$ = driver.buildOperatorName("ror", @1); } ; adding_operator: t_Plus { $$ = driver.buildOperatorName("+", @1); } | t_Minus { $$ = driver.buildOperatorName("-", @1); } | t_Ampersand { $$ = driver.buildOperatorName("&", @1); } ; sign: t_Plus { $$ = driver.buildOperatorName("+", @1); } | t_Minus { $$ = driver.buildOperatorName("-", @1); } ; multiplying_operator: t_Star { $$ = driver.buildOperatorName("*", @1); } | t_Slash { $$ = driver.buildOperatorName("/", @1); } | t_MOD { $$ = driver.buildOperatorName("mod", @1); } | t_REM { $$ = driver.buildOperatorName("rem", @1); } ; primary: normal_name { $$ = $1; } | t_LeftParen expression t_RightParen { $$ = $2; } | literal { $$ = $1; } | aggregate { $$ = $1; } | function_call { $$ = $1; } | type_conversion { $$ = $1; } ; aggregate: t_LeftParen element_association_list t_RightParen { $$ = new ast::Aggregate($2, driver.bl(@1)); } | t_LeftParen named_element_association t_RightParen { $$ = new ast::Aggregate( new std::list(), driver.bl(@1)); $$->associations->push_back($2); } ; element_association_list: element_association t_Comma element_association { $$ = new std::list(); $$->push_back($1); $$->push_back($3); } | element_association_list t_Comma element_association { $$ = $1; $$->push_back($3); } ; element_association: named_element_association { $$ = $1; } | expression { $$ = new ast::ElementAssociation(NULL, $1, driver.bl(@1)); } ; named_element_association: choice_list t_Arrow expression { $$ = new ast::ElementAssociation($1, $3, driver.bl(@2)); /* FIXME names of choice_list may not be accurate */ } ; type_conversion: type_mark t_LeftParen expression t_RightParen { $$ = new ast::TypeConversion($3, $1->declaration, driver.bl(@2)); util::MiscUtil::terminate($1); } ; literal: numeric_literal { $$ = $1; } | string_literal { $$ = $1; } | character_literal { $$ = $1; } | t_NULL { $$ = NULL; /* FIXME? */} ; numeric_literal: abstract_literal { $$ = $1; } | physical_literal { $$ = $1; } ; physical_literal: t_INTEGER normal_name { $$ = new ast::ConstInteger($1, $2, driver.bl(@2)); } | t_REAL normal_name { $$ = new ast::ConstInteger($1, $2, driver.bl(@2)); } ; physical_literal_integer: t_INTEGER normal_name { $$ = new ast::ConstInteger($1, $2, driver.bl(@2)); } | normal_name { $$ = new ast::ConstInteger( static_cast(1), $1, driver.bl(@1)); } ; abstract_literal: t_INTEGER { $$ = new ast::ConstInteger($1, driver.bl(@1)); } | t_REAL { $$ = new ast::ConstReal($1, driver.bl(@1)); } ; string_literal: t_STRING { $$ = ast::NodeFactory::makeAggregateFromString(*$1, driver.bl(@1), driver.nameLookup); } ; character_literal: t_CHAR { ast::SimpleName *sn = new ast::SimpleName( $1, driver.nameLookup.lookup(*$1), driver.bl(@1)); if (sn->candidates.empty()) { ast::UndefinedSymbol *us = new ast::UndefinedSymbol(*$1, driver.bl(@1)); ast::ErrorRegistry::addError(us); } $$ = new ast::FunctionCall( sn, new std::list(), driver.bl(@1)); } ; direction: t_TO { $$ = ast::DiscreteRange::DIRECTION_UP; } | t_DOWNTO { $$ = ast::DiscreteRange::DIRECTION_DOWN; } ; /* --------- sequential statements ---------- */ sequential_statement: sequential_statement_with_label { $$ = $1; } | sequential_statement_without_label { $$ = $1; } ; sequential_statement_without_label: seq_stat t_Semicolon { $$ = $1; assert(driver.label == NULL); } ; sequential_statement_with_label: t_Identifier t_Colon { driver.label = $1->identifier; delete $1; } seq_stat t_Semicolon { $$ = $4; assert(driver.label == NULL); } ; seq_stat: wait_statement { $$ = $1; } | assertion_statement { $$ = $1; } | signal_assign_statement { $$ = $1; } | variable_assign_statement { $$ = $1; } | procedure_call_statement { $$ = $1; } | if_statement { $$ = $1; } | case_statement { $$ = $1; } | loop_statement { $$ = $1; } | next_statement { $$ = $1; } | exit_statement { $$ = $1; } | return_statement { $$ = $1; } | null_statement { $$ = $1; } /* | report_statement */ ; variable_assign_statement: target t_VarAsgn expression { $$ = new ast::VarAssignStat($1, $3, driver.bl(@2)); driver.label = NULL; } ; target: normal_name { $$ = $1; } /* | aggregate */ /* TODO left out for simplicity. each expression of the aggregate would * need to be a variable name */ ; label: t_Identifier { $$ = $1->identifier; delete $1; } ; signal_assign_statement: target t_LESym opt_delaymechanism waveform { $$ = new ast::SigAssignStat($1, $4, driver.bl(@2)); driver.label = NULL; } ; opt_delaymechanism: /* nothing */ | delay_mechanism { assert(false); //TODO } ; delay_mechanism: t_TRANSPORT | t_REJECT expression t_INERTIAL ; waveform: waveform_element_list { $$ = $1; } | t_UNAFFECTED { /* note: only legal in concurrent signal assign statements */ assert(false); //TODO $$ = NULL; } ; waveform_element_list: waveform_element { $$ = new std::list(); $$->push_back($1); } | waveform_element_list t_Comma waveform_element { $$ = $1; $$->push_back($3); } ; waveform_element: expression { $$ = new ast::WaveFormElem($1, NULL, driver.bl(@1)); } | expression t_AFTER expression { $$ = new ast::WaveFormElem($1, $3, driver.bl(@1)); } /* | t_NULL | t_NULL t_AFTER expression // t_NULL included within expression */ ; procedure_call_statement: procedure_call { $$ = $1; driver.label = NULL; } ; procedure_call: procedure_name { $$ = new ast::ProcCallStat($1, new std::list(), driver.bl(@1)); } | procedure_name t_LeftParen actual_parameter_part t_RightParen { $$ = new ast::ProcCallStat($1, $3, driver.bl(@1)); } ; if_statement_begin: t_IF { driver.label = NULL; } ; if_statement: /* 1 */ if_statement_begin /* 2 */ condition /* 3 */ t_THEN /* 4 */ sequence_of_statements /* 5 */ elsif_list /* 6 */ t_ELSE /* 7 */ sequence_of_statements /* 8 */ if_statement_end { $$ = &ast::NodeFactory::createIfStat($2, $4, $5, $7, driver.bl(@1)); } | /* 1 */ if_statement_begin /* 2 */ condition /* 3 */ t_THEN /* 4 */ sequence_of_statements /* 5 */ t_ELSE /* 6 */ sequence_of_statements /* 7 */ if_statement_end { $$ = &ast::NodeFactory::createIfStat($2, $4, NULL, $6, driver.bl(@1)); } | /* 1 */ if_statement_begin /* 2 */ condition /* 3 */ t_THEN /* 4 */ sequence_of_statements /* 5 */ elsif_list /* 6 */ if_statement_end { $$ = &ast::NodeFactory::createIfStat($2, $4, $5, NULL, driver.bl(@1)); } | /* 1 */ if_statement_begin /* 2 */ condition /* 3 */ t_THEN /* 4 */ sequence_of_statements /* 5 */ if_statement_end { $$ = &ast::NodeFactory::createIfStat($2, $4, NULL, NULL, driver.bl(@1)); } ; if_statement_end: t_END t_IF | t_END t_IF label { /* TODO label */ assert(false); } ; elsif_list: t_ELSIF condition t_THEN sequence_of_statements { $$ = &ast::NodeFactory::createNestedElseIfs(NULL, $2, $4, driver.bl(@1)); } | elsif_list t_ELSIF condition t_THEN sequence_of_statements { $$ = &ast::NodeFactory::createNestedElseIfs($1, $3, $5, driver.bl(@2)); } ; condition: expression { $$ = $1; } ; sequence_of_statements: /* nothing */ { $$ = new std::list(); } | sequential_statement_list { $$ = $1; } ; sequential_statement_list: sequential_statement { $$ = new std::list(); $$->push_back($1); } | sequential_statement_list sequential_statement { $$ = $1; $$->push_back($2); } ; case_statement_begin: t_CASE { driver.label = NULL; } ; case_statement: case_statement_begin expression t_IS case_statement_alternative_list t_END t_CASE opt_label { $$ = new ast::CaseStat($2, $4, driver.bl(@1)); /* FIXME opt_label */ } ; opt_label: /* nothing */ { $$ = NULL; } | label { $$ = new ast::SimpleName($1, driver.bl(@1)); } ; case_statement_alternative_list: case_statement_alternative { $$ = new std::list(); $$->push_back($1); } | case_statement_alternative_list case_statement_alternative { $$ = $1; $$->push_back($2); } ; case_statement_alternative: t_WHEN choice_list t_Arrow sequence_of_statements { $$ = new ast::CaseAlternative($2, $4, driver.bl(@1)); } ; loop_statement: loop_statement_begin sequence_of_statements t_END t_LOOP opt_label { $$ = $1; $1->loopStats = $2; /* FIXME opt_label */ driver.symbolTable.popRegion(); } ; loop_statement_begin: iteration_scheme t_LOOP { $$ = $1; driver.label = NULL; } | t_LOOP { /* make while(true) from this. */ driver.symbolTable.pushStdStandard(); ast::SimpleName *sn = new ast::SimpleName( new std::string("true"), driver.symbolTable.lookup("true"), driver.bl(@1)); driver.symbolTable.popRegion(); driver.symbolTable.popRegion(); ast::FunctionCall *fc = new ast::FunctionCall(sn, new std::list(), driver.bl(@1)); $$ = new ast::WhileLoopStat(NULL, NULL, fc, driver.bl(@1)); if (driver.label != NULL) { $$->name = driver.label; driver.symbolTable.registerSymbolWithRegion( ast::SYMBOL_LOOP, *$$); } else { driver.symbolTable.pushNewRegion(); } driver.label = NULL; } ; iteration_scheme: t_WHILE condition { $$ = new ast::WhileLoopStat(NULL, NULL, $2, driver.bl(@1)); if (driver.label != NULL) { $$->name = driver.label; driver.symbolTable.registerSymbolWithRegion( ast::SYMBOL_LOOP, *$$); } else { driver.symbolTable.pushNewRegion(); } } | t_FOR { driver.lookupIdentifiers = false; } t_Identifier { driver.lookupIdentifiers = true; } t_IN discrete_range { ast::ConstantDeclaration *c = new ast::ConstantDeclaration( $3->identifier, NULL, NULL, false, driver.bl(@3)); delete $3; $$ = new ast::ForLoopStat(NULL, NULL, c, $6, driver.bl(@1)); if (driver.label != NULL) { $$->name = driver.label; driver.symbolTable.registerSymbolWithRegion( ast::SYMBOL_LOOP, *$$); } else { driver.symbolTable.pushNewRegion(); } driver.symbolTable.registerSymbol( ast::SYMBOL_VARIABLE, *c); } ; discrete_range: subtype_indication { $$ = new ast::DiscreteRange($1, driver.bl(@1)); } | range { $$ = $1; } ; /* FIXME */ range: range_attribute_name { $$ = new ast::DiscreteRange(NULL, NULL, ast::DiscreteRange::DIRECTION_UP, driver.bl(@1)); $$->rangeName = $1; } | simple_expression direction simple_expression { $$ = new ast::DiscreteRange($1, $3, $2, driver.bl(@2)); } ; next_statement_begin: t_NEXT { driver.label = NULL; } ; next_statement: next_statement_begin opt_label { /* FIXME use true as condition? */ $$ = new ast::NextStat(NULL, $2, driver.bl(@1)); } | next_statement_begin opt_label t_WHEN condition { $$ = new ast::NextStat($4, $2, driver.bl(@1)); } ; exit_statement_begin: t_EXIT { driver.label = NULL; } ; exit_statement: exit_statement_begin label t_WHEN condition { $$ = new ast::ExitStat( new ast::SimpleName($2, driver.bl(@2)), $4, driver.bl(@1)); } | exit_statement_begin label { /* FIXME true as condition? */ $$ = new ast::ExitStat( new ast::SimpleName($2, driver.bl(@2)), NULL, driver.bl(@1)); } | exit_statement_begin t_WHEN condition { $$ = new ast::ExitStat(NULL, $3, driver.bl(@1)); } | exit_statement_begin { /* FIXME true as condition? */ $$ = new ast::ExitStat(NULL, NULL, driver.bl(@1)); } ; return_statement_begin: t_RETURN { driver.label = NULL; } ; return_statement: return_statement_begin expression { $$ = new ast::ReturnStat($2, driver.bl(@1)); if (driver.subprogStack.empty()) { ast::CompileError *err = new ast::CompileError($$->location, "RETURN statementent outside of " "function or procedure"); ast::ErrorRegistry::addError(err); } else { // check if not a function ast::Callable *c = driver.subprogStack.top(); if (c->kind != ast::SubprogBody::PROG_KIND_FUNCTION) { ast::CompileError *err = new ast::CompileError($$->location, "RETURN statement with " "expression in procedure"); ast::ErrorRegistry::addError(err); } $$->enclosingSubprog = c; } } | return_statement_begin { $$ = new ast::ReturnStat(NULL, driver.bl(@1)); if (driver.subprogStack.empty()) { ast::CompileError *err = new ast::CompileError($$->location, "RETURN statementent outside of " "function or procedure"); ast::ErrorRegistry::addError(err); } else { ast::Callable *c = driver.subprogStack.top(); $$->enclosingSubprog = c; } } ; null_statement: t_NULL { $$ = new ast::NullStat(driver.bl(@1)); driver.label = NULL; } ; assertion_statement: assertion { $$ = $1; } ; assertion: t_ASSERT condition t_REPORT expression t_SEVERITY expression { $$ = new ast::AssertStat($2, $4, $6, driver.bl(@1)); driver.label = NULL; } | t_ASSERT condition t_REPORT expression { $$ = new ast::AssertStat($2, $4, NULL, driver.bl(@1)); driver.label = NULL; } | t_ASSERT condition t_SEVERITY expression { $$ = new ast::AssertStat($2, NULL, $4, driver.bl(@1)); driver.label = NULL; } | t_ASSERT condition { $$ = new ast::AssertStat($2, NULL, NULL, driver.bl(@1)); driver.label = NULL; } ; wait_statement: t_WAIT opt_sensitivity_clause opt_condition_clause opt_timeout_clause { $$ = new ast::WaitStat($2, $3, $4, driver.bl(@1)); driver.label = NULL; } ; opt_sensitivity_clause: /* nothing */ { $$ = new std::list(); } | t_ON sensitivity_list { $$ = $2; } ; sensitivity_list: normal_name /* signal name */ { $$ = new std::list(); $$->push_back($1); } | sensitivity_list t_Comma normal_name { $$ = $1; $$->push_back($3); } ; opt_condition_clause: /* nothing */ { $$ = NULL; } | t_UNTIL condition { $$ = $2; } ; opt_timeout_clause: /* nothing */ { $$ = NULL; } | t_FOR expression { /* time_expression */ $$ = $2; } ; /* ------------ concurrent statements ----------- */ concurrent_statement_with_label_begin: t_Identifier t_Colon { $$ = $1->identifier; delete $1; driver.label = $$; } ; concurrent_statement: concurrent_statement_with_label_begin concurrent_statement_label_optional { $$ = $2; $$->name = $1; driver.label = NULL; } | concurrent_statement_with_label_begin concurrent_statement_label_mandatory { $$ = $2; $$->name = $1; driver.label = NULL; } | concurrent_statement_label_optional { $$ = $1; } ; concurrent_statement_label_optional: process_statement { $$ = $1; } | concurrent_signal_assignment_statement { $$ = $1; } /* | concurrent_procedure_call_statement | concurrent_assertion_statement */ ; concurrent_statement_label_mandatory: component_instantiation_statement { $$ = $1; } /* | block_statement | generate_statement */ ; concurrent_signal_assignment_statement: t_POSTPONED conditional_signal_assignment { $$ = $2; assert(false); /* TODO postponed */ } | conditional_signal_assignment { $$ = $1; } | t_POSTPONED selected_signal_assignment { $$ = $2; assert(false); /* TODO postponed */ } | selected_signal_assignment { $$ = $1; } ; conditional_signal_assignment: target t_LESym options conditional_waveforms t_Semicolon { $$ = &ast::NodeFactory::makeCondalSigAssign(*$1, *$4, driver.bl(@2)); } ; options: opt_guarded opt_delay_mechanism ; opt_guarded: /* nothing */ { $$ = false; } | t_GUARDED { $$ = true; assert(false); /* FIXME */ } ; opt_delay_mechanism: /* nothing */ | delay_mechanism { assert(false); /* TODO */ } ; conditional_waveforms: waveform { $$ = new ast::SigAssignStat(NULL, $1, driver.bl(@1)); } | waveform t_WHEN condition { ast::SigAssignStat* s = new ast::SigAssignStat(NULL, $1, driver.bl(@1)); std::list* ll = new std::list(); ll->push_back(s); $$ = new ast::IfStat($3, ll, NULL, driver.bl(@2)); } | waveform t_WHEN condition t_ELSE conditional_waveforms { ast::SigAssignStat* s = new ast::SigAssignStat(NULL, $1, driver.bl(@1)); std::list* ll = new std::list(); ll->push_back(s); std::list* lr = new std::list(); lr->push_back($5); $$ = new ast::IfStat($3, ll, lr, driver.bl(@2)); } ; selected_signal_assignment: t_WITH expression t_SELECT target t_LESym options selected_waveforms t_Semicolon { ast::CaseStat* c = new ast::CaseStat($2, $7, driver.bl(@1)); $$ = &ast::NodeFactory::makeCondalSigAssign(*$4, *c, driver.bl(@5)); } ; selected_waveforms: selected_waveform_list { $$ = $1; } ; selected_waveform_list: waveform t_WHEN choice_list { ast::SigAssignStat* s = new ast::SigAssignStat(NULL, $1, driver.bl(@1)); std::list* l = new std::list(); l->push_back(s); $$ = new std::list(); $$->push_back(new ast::CaseAlternative($3, l, driver.bl(@2))); } | selected_waveform_list t_Comma waveform t_WHEN choice_list { ast::SigAssignStat* s = new ast::SigAssignStat(NULL, $3, driver.bl(@3)); std::list* l = new std::list(); l->push_back(s); $$ = $1; $$->push_back(new ast::CaseAlternative($5, l, driver.bl(@4))); } ; opt_postponed: /* nothing */ { $$ = false; } | t_POSTPONED { $$ = true; assert(false); /* FIXME */ } ; opt_sensitivity_list: /* nothing */ { $$ = NULL; } | t_LeftParen sensitivity_list t_RightParen { $$ = $2; } ; component_instantiation_statement: instantiated_unit opt_generic_map_aspect opt_port_map_aspect t_Semicolon { $$ = new ast::CompInstStat($1, $2, $3, driver.bl(@1)); // lookup formal parts ast::ResolveSymbols rs = ast::ResolveSymbols(driver.symbolTable); $$->accept(rs); } ; instantiated_unit: t_COMPONENT normal_name { $$ = $2; } | normal_name { $$ = $1; } /* | t_ENTITY name t_LeftParen t_Identifier t_RightParen //FIXME conflict to name with braces | t_ENTITY name | t_CONFIGURATION name //TODO */ ; opt_generic_map_aspect: /* nothing */ { $$ = new std::list(); } | generic_map_aspect { $$ = $1; } ; opt_port_map_aspect: /* nothing */ { $$ = new std::list(); } | port_map_aspect { $$ = $1; } ; generic_map_aspect: t_GENERIC t_MAP t_LeftParen association_list t_RightParen { $$ = $4; } ; port_map_aspect: t_PORT t_MAP t_LeftParen association_list t_RightParen { $$ = $4; } ; association_list: association_element { $$ = new std::list(); $$->push_back($1); } | association_list t_Comma association_element { $$ = $1; $$->push_back($3); } ; function_association_list: function_association_element { $$ = new std::list(); $$->push_back($1); } | function_association_list t_Comma function_association_element { $$ = $1; $$->push_back($3); } ; function_association_element: function_formal_part t_Arrow actual_part { $$ = new ast::AssociationElement($1, $3, driver.bl(@2)); } | actual_part { $$ = new ast::AssociationElement(NULL, $1, driver.bl(@1)); } ; association_element: formal_part t_Arrow actual_part { $$ = new ast::AssociationElement($1, $3, driver.bl(@2)); } | actual_part { $$ = new ast::AssociationElement(NULL, $1, driver.bl(@1)); } ; function_formal_part: formal_designator { $$ = $1; } /* no conversion function/type_conversion considered, as functions can have only parameters of mode "in" */ ; formal_part: formal_designator { $$ = $1; } /* | function_name t_LeftParen formal_designator t_RightParen { $$ = $3; } | type_mark t_LeftParen formal_designator t_RightParen { $$ = $3; } */ /* FIXME conflicts */ ; formal_designator: normal_name { $$ = $1; } | function_name { $$ = $1; } | type_name { $$ = $1; } | procedure_name { $$ = $1; } ; /* FIXME handled via expression already. Is there some semantic difference anyways? */ actual_part: actual_designator { $$ = $1; } /* | function_name t_LeftParen actual_designator t_RightParen | type_mark t_LeftParen actual_designator t_RightParen */ ; actual_designator: expression { $$ = $1; } /* | file_name */ | t_OPEN { $$ = NULL; } ; process_statement_begin: opt_postponed t_PROCESS { $$ = new ast::Process(NULL, NULL, NULL, driver.bl(@2)); if (driver.label != NULL) { $$->name = driver.label; driver.label = NULL; driver.symbolTable.registerSymbolWithRegion( ast::SYMBOL_PROCESS, *$$); } else { driver.symbolTable.pushNewRegion(); } } ; process_statement: process_statement_begin opt_sensitivity_list opt_t_is process_declarative_part t_BEGIN process_statement_part t_END opt_postponed t_PROCESS opt_label t_Semicolon { $$ = $1; $1->sensitivityList = $2; $1->declarations = $4; $1->seqStats = $6; driver.symbolTable.popRegion(); } ; opt_t_is: /* nothing */ | t_IS ; process_declarative_part: /* nothing */ { $$ = new std::list(); } | process_declarative_item_list { $$ = $1; } ; process_statement_part: sequence_of_statements { $$ = $1; } ; process_declarative_item_list: process_declarative_item { $$ = $1; } | process_declarative_item_list process_declarative_item { ast::NodeFactory::listCombine($1, $2); delete $2; $$ = $1; } ; process_declarative_item: subprogram_declaration { $$ = new std::list(); $$->push_back($1); } | subprogram_body { $$ = new std::list(); if (! $1->seen) { $$->push_back($1); } } | type_declaration { $$ = $1->flatten(); delete $1; } | subtype_declaration { $$ = new std::list(); $$->push_back($1); } | constant_declaration { $$ = $1; } | variable_declaration { $$ = $1; } | attribute_specification { $$ = new std::list(); $$->push_back($1); } | attribute_declaration { $$ = $1; } /* | file_declaration | alias_declaration | use_clause | group_template_declaration | group_declaration */ ; attribute_declaration: t_ATTRIBUTE designator t_Colon type_mark t_Semicolon { ast::AttributeDeclaration *a = new ast::AttributeDeclaration( $2, $4, driver.bl(@1)); $$ = new std::list(); $$->push_back(a); driver.symbolTable.registerSymbol(ast::SYMBOL_ATTRIBUTE, *a); } ; subprogram_declaration: subprogram_specification t_Semicolon { $$ = $1; if ($1->kind == ast::SubprogBody::PROG_KIND_FUNCTION) { driver.symbolTable.registerSymbolWithRegion( ast::SYMBOL_FUNCTION, *$1); } else { driver.symbolTable.registerSymbolWithRegion( ast::SYMBOL_PROCEDURE, *$1); } /* register parameter */ if ($1->arguments) { driver.registerSymbolDecls( $1->arguments, ast::SYMBOL_PARAMETER); } /* leave the region immediately again */ driver.symbolTable.popRegion(); } ; subprogram_body_begin: subprogram_specification t_IS { $$ = driver.nameLookup.findOrRegisterSubprog($1); driver.subprogStack.push($$); } ; subprogram_body: subprogram_body_begin subprogram_declarative_part t_BEGIN subprogram_statement_part t_END opt_subprogram_kind opt_designator t_Semicolon { $$ = $1; $1->definition = new ast::SubprogBody($2, $4, driver.bl(@1)); /* FIXME opt_designator */ /* leave region of subprogram again */ driver.symbolTable.popRegion(); driver.subprogStack.pop(); } ; opt_designator: /* nothing */ { $$ = NULL; } | designator { $$ = $1; } ; opt_subprogram_kind: /* nothing */ { $$ = ast::SubprogBody::PROG_KIND_UNKNOWN; } | subprogram_kind { $$ = $1; } ; subprogram_kind: t_PROCEDURE { $$ = ast::SubprogBody::PROG_KIND_PROCEDURE; } | t_FUNCTION { $$ = ast::SubprogBody::PROG_KIND_FUNCTION; } ; pure_or_impure: /* nothing */ { $$ = true; } | t_PURE { $$ = true; } | t_IMPURE { $$ = false; } ; subprogram_specification: /* 1 */ t_PROCEDURE { driver.lookupIdentifiers = false; } /* 3 */ designator { driver.lookupIdentifiers = true; } /* 5 */ opt_formal_proc_parameter_list { $$ = new ast::ProcedureDeclaration($3, $5, driver.bl(@1)); } | /* 1 */ pure_or_impure /* 2 */ t_FUNCTION { driver.lookupIdentifiers = false; } /* 4 */ designator { driver.lookupIdentifiers = true; } /* 6 */ opt_formal_func_parameter_list /* 7 */ t_RETURN /* 8 */ type_mark { $$ = new ast::FunctionDeclaration($4, $6, $8, $1, driver.bl(@2)); } ; opt_formal_func_parameter_list: /* nothing */ { $$ = NULL; } | t_LeftParen formal_func_parameter_list t_RightParen { $$ = $2; } ; opt_formal_proc_parameter_list: /* nothing */ { $$ = NULL; } | t_LeftParen formal_proc_parameter_list t_RightParen { $$ = $2; } ; designator: t_Identifier { $$ = $1->identifier; } | operator_symbol { $$ = $1; } | ID_function { $$ = $1->identifier; } | ID_procedure { $$ = $1->identifier; } ; operator_symbol: t_STRING { $$ = $1; } ; type_mark: type_name { /* type name or subtype name */ $$ = new ast::SubtypeIndication($1, driver.bl(@1)); } ; subprogram_declarative_part: /* nothing */ { $$ = NULL; } | subprogram_declarative_item_list { $$ = $1; } ; subprogram_declarative_item_list: subprogram_declarative_item { $$ = $1; } | subprogram_declarative_item_list subprogram_declarative_item { $$ = $1; ast::NodeFactory::listCombine($1, $2); delete $2; } ; subprogram_declarative_item: subprogram_declaration { $$ = new std::list(); $$->push_back($1); } | subprogram_body { $$ = new std::list(); if (! $1->seen) { $$->push_back($1); } } | type_declaration { $$ = $1->flatten(); delete $1; } | subtype_declaration { $$ = new std::list(); $$->push_back($1); } | constant_declaration { $$ = $1; } | variable_declaration { $$ = $1; } | attribute_specification { $$ = new std::list(); $$->push_back($1); } | attribute_declaration { $$ = $1; } /* | file_declaration | alias_declaration | use_clause | group_template_declaration | group_declaration TODO */ ; subprogram_statement_part: sequence_of_statements { $$ = $1; } ; formal_proc_parameter_list: proc_interface_element { $$ = $1; } | formal_proc_parameter_list t_Semicolon proc_interface_element { $$ = $1; ast::NodeFactory::listCombine($1, $3); delete $3; } ; formal_func_parameter_list: func_interface_element { $$ = $1; } | formal_func_parameter_list t_Semicolon func_interface_element { $$ = $1; ast::NodeFactory::listCombine($1, $3); delete $3; } ; func_interface_element: /* 1 */ opt_element_kind /* 2 */ identifier_list /* 3 */ t_Colon /* 4 */ opt_mode /* 5 */ subtype_indication /* 6 */ opt_bus /* 7 */ opt_initializer { $$ = &ast::NodeFactory::makeFuncInterfaceDecls( *$2, $7, $4, $1, $5, driver.bl(@2)); } ; proc_interface_element: /* 1 */ opt_element_kind /* 2 */ identifier_list /* 3 */ t_Colon /* 4 */ opt_mode /* 5 */ subtype_indication /* 6 */ opt_bus /* 7 */ opt_initializer { $$ = &ast::NodeFactory::makeProcInterfaceDecls( *$2, $7, $4, $1, $5, driver.bl(@2)); } ; opt_element_kind: /* nothing */ { $$ = ast::ValDeclaration::OBJ_CLASS_UNSPECIFIED; } | element_kind { $$ = $1; } ; element_kind: t_CONSTANT { $$ = ast::ValDeclaration::OBJ_CLASS_CONSTANT; } | t_VARIABLE { $$ = ast::ValDeclaration::OBJ_CLASS_VARIABLE; } | t_SIGNAL { $$ = ast::ValDeclaration::OBJ_CLASS_SIGNAL; } /* | t_FILE */ ; opt_mode: /* nothing */ { $$ = ast::ValDeclaration::MODE_IN; } | mode { $$ = $1; } ; opt_bus: /* nothing */ | t_BUS ; opt_initializer: /* nothing */ { $$ = NULL; } | t_VarAsgn expression { $$ = $2; } ; mode: t_IN { $$ = ast::ValDeclaration::MODE_IN; } | t_OUT { $$ = ast::ValDeclaration::MODE_OUT; } | t_INOUT { $$ = ast::ValDeclaration::MODE_INOUT; } /* | t_BUFFER | t_LINKAGE */ ; subtype_indication: type_mark { $$ = $1; } | type_mark constraint { $$ = $1; $$->constraint = $2->rangeConstraint; $$->indexConstraint = $2->indexConstraint; delete $2; } | function_name type_mark { $$ = $2; $$->resolutionFunction = $1; } | function_name type_mark constraint { $$ = $2; $$->resolutionFunction = $1; $$->constraint = $3->rangeConstraint; $$->indexConstraint = $3->indexConstraint; delete $3; } ; constraint: range_constraint { $$ = new ast::NodeFactory::Constraint(); $$->rangeConstraint = $1; $$->indexConstraint = NULL; } | index_constraint { $$ = new ast::NodeFactory::Constraint(); $$->rangeConstraint = NULL; $$->indexConstraint = $1; } ; range_constraint: t_RANGE discrete_range { $$ = $2; } ; subtype_declaration: /* 1 */ t_SUBTYPE { driver.lookupIdentifiers = false; } /* 3 */ t_Identifier /* 4 */ t_IS { driver.lookupIdentifiers = true; } /* 6 */ subtype_indication /* 7 */ t_Semicolon { $$ = $6; $$->name = $3->identifier; delete $3; $$->location = driver.bl(@1); driver.symbolTable.registerSymbol(ast::SYMBOL_TYPE, *$$); } ; /* ----------------------- types ---------------------- */ type_declaration: full_type_declaration { $$ = $1; } /* | incomplete_type_definition TODO */ ; full_type_declaration: t_TYPE { driver.lookupIdentifiers = false; } t_Identifier { driver.lookupIdentifiers = true; } t_IS type_definition t_Semicolon { $$ = $6; $$->registerType(driver.symbolTable, $3); } ; type_definition: scalar_type_definition { $$ = $1; } | composite_type_definition { $$ = $1; } /* | access_type_definition | file_type_definition | protected_type_definition TODO */ ; scalar_type_definition: enumeration_type_definition { $$ = $1; } | number_type_definition { $$ = $1; } | physical_type_definition { $$ = $1; } ; enumeration_type_definition: t_LeftParen { driver.lookupIdentifiers = false; } enumeration_literal_list t_RightParen { $$ = new ast::NodeFactory::TypeDeclHelper( new ast::EnumerationType(NULL, $3, driver.bl(@1))); driver.lookupIdentifiers = true; } ; enumeration_literal_list: enumeration_literal_decl { $$ = new std::list(); $$->push_back($1); } | enumeration_literal_list t_Comma enumeration_literal_decl { $$ = $1; $$->push_back($3); } ; enumeration_literal_decl: t_Identifier { $$ = new ast::FunctionDeclaration( $1->identifier, NULL, NULL, /* will be set later */ true, driver.bl(@1)); delete $1; } | t_CHAR { $$ = new ast::FunctionDeclaration( $1, NULL, NULL, /* will be set later */ true, driver.bl(@1)); } ; number_type_definition: range_constraint { $$ = new ast::NodeFactory::TypeDeclHelper( new ast::RangeConstraintType(NULL, $1, driver.bl(@1)) ); } ; physical_type_definition: /* 1 */ range_constraint /* 2 */ t_UNITS { driver.lookupIdentifiers = false; } /* 4 */ primary_unit_definition /* 5 */ opt_secondary_unit_declaration_list /* 6 */ t_END { driver.lookupIdentifiers = true; } /* 8 */ t_UNITS /* 9 */ opt_physical_type_simple_name { $5->push_front($4); $$ = new ast::NodeFactory::TypeDeclHelper( new ast::PhysicalType(NULL, $1, $5, driver.bl(@4))); } ; opt_physical_type_simple_name: /* nothing */ { $$ = NULL; } | simple_name { $$ = $1; } ; primary_unit_definition: t_Identifier t_Semicolon { $$ = new ast::PhysicalTypeUnit($1->identifier, NULL, driver.bl(@1)); driver.symbolTable.registerSymbol(ast::SYMBOL_UNIT, *$$); std::cerr << "registering " << *$1->identifier << std::endl; } ; opt_secondary_unit_declaration_list: /* nothing */ { $$ = new std::list(); } | secondary_unit_declaration_list { $$ = $1; } ; secondary_unit_declaration_list: secondary_unit_declaration { $$ = new std::list(); $$->push_back($1); } | secondary_unit_declaration_list secondary_unit_declaration { $$ = $1; $$->push_back($2); } secondary_unit_declaration: t_Identifier { driver.lookupIdentifiers = true; } t_EQSym physical_literal_integer { driver.lookupIdentifiers = false; } t_Semicolon { $$ = new ast::PhysicalTypeUnit($1->identifier, $4, driver.bl(@1)); driver.symbolTable.registerSymbol(ast::SYMBOL_UNIT, *$$); } ; composite_type_definition: array_type_definition { $$ = $1; } | record_type_definition { $$ = $1; } ; array_type_definition: unconstrained_array_definition { $$ = $1; } | constrained_array_definition { $$ = $1; } ; unconstrained_array_definition: t_ARRAY t_LeftParen index_subtype_definition_list t_RightParen t_OF subtype_indication { $$ = new ast::NodeFactory::TypeDeclHelper( new ast::UnconstrainedArrayType( NULL, $3, $6, driver.bl(@1))); } ; index_subtype_definition_list: index_subtype_definition { $$ = new std::list(); $$->push_back($1); } | index_subtype_definition_list t_Comma index_subtype_definition { $$ = $1; $$->push_back($3); } ; index_subtype_definition: type_mark t_RANGE t_Box { $$ = $1; } ; constrained_array_definition: t_ARRAY index_constraint t_OF subtype_indication { $$ = new ast::NodeFactory::TypeDeclHelper($2, $4, driver.bl(@1), driver.symbolTable); } ; index_constraint: t_LeftParen discrete_range_list t_RightParen { $$ = $2; } ; discrete_range_list: discrete_range { $$ = new std::list(); $$->push_back($1); } | discrete_range_list t_Comma discrete_range { $$ = $1; $$->push_back($3); } ; record_type_definition: t_RECORD { /* register symbol */ driver.symbolTable.pushNewRegion(); } element_declaration_list t_END t_RECORD { $$ = new ast::NodeFactory::TypeDeclHelper( new ast::RecordType(NULL, $3, driver.bl(@1))); } ; element_declaration_list: element_declaration { $$ = $1; } | element_declaration_list element_declaration { $$ = $1; ast::NodeFactory::listCombine($1, $2); delete $2; } ; element_declaration: identifier_list t_Colon element_subtype_definition t_Semicolon { $$ = &ast::NodeFactory::makeRecordTypeElements(*$1, *$3, driver.bl(@1)); driver.registerSymbolDecls($$, ast::SYMBOL_ELEMENT); delete $1; } ; element_subtype_definition: subtype_indication { $$ = $1; } ; /* ---------------------- various declarative items --------------------- */ /* FIXME lrm 2.6, 4.3.1.1: deferred constants get redefined in the package body, and lack an initializer in the package itself. */ constant_declaration: t_CONSTANT identifier_list t_Colon subtype_indication t_VarAsgn expression t_Semicolon { std::list *l; l = &ast::NodeFactory::makeConstantDecls(*$2, $6, $4, driver.bl(@1)); delete $2; $$ = ast::NodeFactory::listCast(l); driver.registerSymbolDecls($$, ast::SYMBOL_VARIABLE); } ; variable_declaration: /* 1 */ opt_shared /* 2 */ t_VARIABLE /* 3 */ identifier_list /* 4 */ t_Colon /* 5 */ subtype_indication /* 6 */ opt_initializer /* 7 */ t_Semicolon { $$ = &ast::NodeFactory::makeVarDecls(*$3, $6, $5, driver.bl(@2)); driver.registerSymbolDecls($$, ast::SYMBOL_VARIABLE); delete $3; } ; signal_declaration: /* 1 */ t_SIGNAL /* 2 */ identifier_list /* 3 */ t_Colon /* 4 */ subtype_indication /* 5 */ opt_signal_kind /* 6 */ opt_initializer /* 7 */ t_Semicolon { std::list* l; l = &ast::NodeFactory::makeSignalDecls(*$2, ast::ValDeclaration::MODE_INOUT, false, $6, $4, driver.bl(@1)); delete $2; $$ = ast::NodeFactory::listCast(l); driver.registerSymbolDecls($$, ast::SYMBOL_SIGNAL); } ; opt_signal_kind: /* nothing */ | t_REGISTER { assert(false); /* FIXME */ } | t_BUS { assert(false); /* FIXME */ } ; opt_shared: /* nothing */ { $$ = false; } | t_SHARED { $$ = true; assert(false); /* TODO */ } ; entity_decl_begin_1: t_ENTITY { driver.lookupIdentifiers = false; } ; entity_decl_begin_2: t_Identifier t_IS { $$ = $1; driver.lookupIdentifiers = true; } ; entity_decl_begin: entity_decl_begin_1 entity_decl_begin_2 { $$ = new ast::Entity($2->identifier, NULL, NULL, NULL, NULL, NULL, driver.bl(@1)); driver.symbolTable.lateRegisterAttach( ast::SYMBOL_ENTITY, *$$); } entity_declaration: entity_decl_begin opt_generic_clause opt_port_clause entity_declarative_part opt_entity_statement_part t_END opt_t_entity opt_simple_declaration_name t_Semicolon { $$ = $1; $$->generics = $2; $$->ports = $3; $$->declarations = $4; /* FIXME entity_statement_part */ } ; opt_simple_declaration_name: /* nothing */ { $$ = NULL; } | simple_name { $$ = $1; } ; opt_t_entity: /* nothing */ | t_ENTITY ; opt_entity_statement_part: /* nothing */ { $$ = NULL; } | t_BEGIN entity_statement_part { /* FIXME entity_statement_part */ assert(false); $$ = $2; } ; opt_generic_clause: /* nothing */ { $$ = new std::list(); } | generic_clause { $$ = $1; } ; opt_port_clause: /* nothing */ { $$ = new std::list(); } | port_clause { $$ = $1; } ; generic_clause: t_GENERIC t_LeftParen generic_list t_RightParen t_Semicolon { $$ = $3; } ; port_clause: t_PORT t_LeftParen port_list t_RightParen t_Semicolon { $$ = $3; } ; generic_list: generic_interface_element { $$ = $1; } | generic_list t_Semicolon generic_interface_element { $$ = $1; ast::NodeFactory::listCombine($1, $3); delete $3; } ; generic_interface_element: /* 1 */ opt_t_constant /* 2 */ identifier_list /* 3 */ t_Colon /* 4 */ opt_t_in /* 5 */ subtype_indication /* 6 */ opt_initializer { $$ = &ast::NodeFactory::makeConstantDecls(*$2, $6, $5, driver.bl(@2)); driver.registerSymbolDecls($$, ast::SYMBOL_PARAMETER); delete $2; /* generics can change for each instantiated component... */ for (std::list::iterator i = $$->begin(); i != $$->end(); i++) { (*i)->fixedValue = false; } } ; port_list: port_interface_element { $$ = $1; } | port_list t_Semicolon port_interface_element { $$ = $1; ast::NodeFactory::listCombine($1, $3); delete $3; } ; opt_t_constant: /* nothing */ | t_CONSTANT ; opt_t_in: /* nothing */ | t_IN ; port_interface_element: /* 1 */ opt_t_signal /* 2 */ identifier_list /* 3 */ t_Colon /* 4 */ opt_mode /* 5 */ subtype_indication /* 6 */ opt_t_bus /* 7 */ opt_initializer { $$ = &ast::NodeFactory::makeSignalDecls(*$2, $4, $6, $7, $5, driver.bl(@2)); /* FIXME signal? */ driver.registerSymbolDecls($$, ast::SYMBOL_PORT); delete $2; } | /* just for better error messages ($5 must be a type_name/subtype_indication) */ opt_t_signal identifier_list t_Colon opt_mode t_Identifier opt_t_bus opt_initializer { std::string *msg = new std::string("'"); *msg += *$5->identifier; *msg += "' does not denote a type."; driver.error(@5, *msg); $$ = NULL; } ; opt_t_bus: /* nothing */ { $$ = false; } | t_BUS { $$ = true; } ; opt_t_signal: /* nothing */ | t_SIGNAL ; entity_declarative_part: /* nothing */ { $$ = NULL; } | entity_declarative_item_list { $$ = $1; } ; entity_declarative_item_list: entity_declarative_item { $$ = $1; } | entity_declarative_item_list entity_declarative_item { $$ = $1; ast::NodeFactory::listCombine($1, $2); delete $2; } ; entity_declarative_item: subprogram_declaration { $$ = new std::list(); $$->push_back($1); } | subprogram_body { $$ = new std::list(); if (! $1->seen) { $$->push_back($1); } } | type_declaration { $$ = $1->flatten(); delete $1; } | subtype_declaration { $$ = new std::list(); $$->push_back($1); } | constant_declaration { $$ = $1; } | signal_declaration { $$ = $1; } | attribute_specification { $$ = new std::list(); $$->push_back($1); } | attribute_declaration { $$ = $1; } /* | shared_variable_declaration | file_declaration | alias_declaration | disconnection_specification | use_clause | group_template_declaration | group_declaration TODO */ ; entity_statement_part: /* nothing */ { $$ = NULL; } | entity_statement_list { $$ = $1; } ; entity_statement_list: entity_statement { $$ = new std::list(); $$->push_back($1); } | entity_statement_list entity_statement { $$ = $1; $$->push_back($2); } ; entity_statement_with_label_begin: t_Identifier t_Colon { $$ = $1->identifier; delete $1; driver.label = $$; } ; entity_statement: process_statement { $$ = $1; } | entity_statement_with_label_begin process_statement { $$ = $2; $$->name = $1; driver.label = NULL; } /* | concurrent_assertion_stat | label t_Colon concurrent_assertion_stat | concurrent_procedure_call | label t_Colon concurrent_procedure_call */ ; t_package_no_lookup: t_PACKAGE { driver.lookupIdentifiers = false; } ; package_decl_begin: /* 1 */ t_package_no_lookup /* 2 */ t_Identifier /* 3 */ t_IS { driver.lookupIdentifiers = true; $$ = new ast::Package($2->identifier, NULL, NULL, NULL, driver.bl(@1)); driver.symbolTable.lateRegisterAttach( ast::SYMBOL_PACKAGE, *$$); } ; package_declaration: package_decl_begin package_declarative_part t_END opt_t_package opt_package_simple_name t_Semicolon { $$ = $1; $$->declarations = $2; } ; opt_t_package: /* nothing */ | t_PACKAGE ; opt_package_simple_name: /* nothing */ | t_Identifier ; package_declarative_part: /* nothing */ { $$ = NULL; } | package_declarative_item_list { $$ = $1; } ; package_declarative_item_list: package_declarative_item { $$ = $1; } | package_declarative_item_list package_declarative_item { $$ = $1; ast::NodeFactory::listCombine($1, $2); delete $2; } ; package_declarative_item: subprogram_declaration { $$ = new std::list(); $$->push_back($1); } | type_declaration { $$ = $1->flatten(); delete $1; } | subtype_declaration { $$ = new std::list(); $$->push_back($1); } | constant_declaration { $$ = $1; } | signal_declaration { $$ = $1; } | variable_declaration { $$ = $1; } | attribute_specification { $$ = new std::list(); $$->push_back($1); } | attribute_declaration { $$ = $1; } /* | file_declaration | alias_declaration | component_declaration | disconnection_specification | use_clause | group_template_declaration | group_declaration */ ; architecture_body_begin_1: t_ARCHITECTURE { driver.lookupIdentifiers = false; } ; architecture_body_begin_2: t_Identifier t_OF { $$ = $1; driver.lookupIdentifiers = true; } ; architecture_body_begin: architecture_body_begin_1 architecture_body_begin_2 normal_name t_IS { $$ = new ast::Architecture($2->identifier, $3, NULL, NULL, NULL, NULL, driver.bl(@1)); driver.nameLookup.openRegion($3); driver.symbolTable.flipStack(); driver.symbolTable.lateRegisterAttach( ast::SYMBOL_ARCHITECTURE, *$$); } ; architecture_body: architecture_body_begin architecture_declarative_part t_BEGIN architecture_statement_part t_END opt_t_architecture opt_simple_declaration_name t_Semicolon { $$ = $1; $$->declarations = $2; $$->concurrentStats = $4; //region of architecture driver.symbolTable.popRegion(); //region of entity handled by design unit } ; opt_t_architecture: /* nothing */ | t_ARCHITECTURE ; architecture_declarative_part: /* nothing */ { $$ = new std::list(); } | block_declarative_item_list { $$ = $1; } ; block_declarative_item_list: block_declarative_item { $$ = $1; } | block_declarative_item_list block_declarative_item { $$ = $1; ast::NodeFactory::listCombine($1, $2); delete $2; } ; block_declarative_item: subprogram_declaration { $$ = new std::list(); $$->push_back($1); } | subprogram_body { $$ = new std::list(); if (! $1->seen) { $$->push_back($1); } } | type_declaration { $$ = $1->flatten(); delete $1; } | subtype_declaration { $$ = new std::list(); $$->push_back($1); } | constant_declaration { $$ = $1; } | signal_declaration { $$ = $1; } | variable_declaration { $$ = $1; } | attribute_specification { $$ = new std::list(); $$->push_back($1); } | attribute_declaration { $$ = $1; } /* | file_declaration | alias_declaration | component_declaration | configuration_specification | disconnection_specification | use_clause | group_template_declaration | group_declaration */ ; architecture_statement_part: /* nothing */ { $$ = NULL; } | architecture_statement_list { $$ = $1; } ; architecture_statement_list: concurrent_statement { $$ = new std::list(); $$->push_back($1); } | architecture_statement_list concurrent_statement { $$ = $1; $$->push_back($2); } ; package_body_begin: /* 1 */ t_package_no_lookup /* 2 */ t_BODY { driver.lookupIdentifiers = true; } /* 4 */ simple_name /* 5 */ t_IS { $$ = new ast::PackageBody($4->name, NULL, NULL, NULL, driver.bl(@1)); driver.nameLookup.openRegion($4); driver.symbolTable.flipStack(); } package_body: package_body_begin package_body_declarative_part t_END opt_t_package opt_simple_declaration_name t_Semicolon { $$ = $1; $$->declarations = $2; // package body driver.symbolTable.popRegion(); // package itself stays on the stack, handled by design_unit } ; package_body_declarative_part: /* nothing */ { $$ = NULL; } | package_body_declarative_item_list { $$ = $1; } ; package_body_declarative_item_list: package_body_declarative_item { $$ = $1; } | package_body_declarative_item_list package_body_declarative_item { $$ = $1; ast::NodeFactory::listCombine($1, $2); delete $2; } ; package_body_declarative_item: subprogram_declaration { $$ = new std::list(); $$->push_back($1); } | subprogram_body { $$ = new std::list(); if (! $1->seen) { $$->push_back($1); } } | type_declaration { $$ = $1->flatten(); delete $1; } | subtype_declaration { $$ = new std::list(); $$->push_back($1); } | constant_declaration { $$ = $1; } | variable_declaration { $$ = $1; } /* | file_declaration | alias_declaration | use_clause | group_template_declaration | group_declaration */ ; attribute_specification: /* 1 */ t_ATTRIBUTE /* 2 */ attribute_designator /* 3 */ t_OF /* 4 */ entity_name_list /* 5 */ t_Colon /* 6 */ entity_class /* 7 */ t_IS /* 8 */ expression /* 9 */ t_Semicolon { $$ = ast::NodeFactory::handleAttributeSpecs($2, *$4, $6, $8, driver.symbolTable); delete $4; } ; entity_class: t_ENTITY { $$ = ast::NodeFactory::EC_ENTITY; } | t_ARCHITECTURE { $$ = ast::NodeFactory::EC_ARCHITECTURE; } | t_CONFIGURATION { $$ = ast::NodeFactory::EC_CONFIGURATION; } | t_PROCEDURE { $$ = ast::NodeFactory::EC_PROCEDURE; } | t_FUNCTION { $$ = ast::NodeFactory::EC_FUNCTION; } | t_PACKAGE { $$ = ast::NodeFactory::EC_PACKAGE; } | t_TYPE { $$ = ast::NodeFactory::EC_TYPE; } | t_SUBTYPE { $$ = ast::NodeFactory::EC_SUBTYPE; } | t_CONSTANT { $$ = ast::NodeFactory::EC_CONSTANT; } | t_SIGNAL { $$ = ast::NodeFactory::EC_SIGNAL; } | t_VARIABLE { $$ = ast::NodeFactory::EC_VARIABLE; } | t_COMPONENT { $$ = ast::NodeFactory::EC_COMPONENT; } | t_LABEL { $$ = ast::NodeFactory::EC_LABEL; } | t_LITERAL { $$ = ast::NodeFactory::EC_LITERAL; } | t_UNITS { $$ = ast::NodeFactory::EC_UNITS; } | t_GROUP { $$ = ast::NodeFactory::EC_GROUP; } | t_FILE { $$ = ast::NodeFactory::EC_FILE; } ; /* FIXME */ entity_name_list: entity_designator_list { $$ = $1; } /* | t_OTHERS */ /* | t_ALL */ ; entity_designator_list: entity_designator { $$ = new std::list(); $$->push_back($1); } | entity_designator_list t_Comma entity_designator { $$ = $1; $$->push_back($3); } ; entity_designator: entity_tag /* opt_signature */ { $$ = $1; } ; entity_tag: simple_name { $$ = $1; } /* | character_literal | operator_symbol */ ; attribute_designator: simple_name { $$ = $1; } ; %% /* forward to driver */ void yy::FAUhdlParser::error(const yy::FAUhdlParser::location_type& l, const std::string& m) { driver.error(l, m); } fauhdlc-20130704/frontend/newparser/ParserDriver.tpp0000664000175000017500000000576111137620345021777 0ustar potyrapotyra/* $Id: ParserDriver.tpp 4331 2009-01-27 14:57:41Z potyra $ * vim:tabstop=8:shiftwidth=8:filetype=cpp:textwidth=72: * * ParserDriver: glue class to driver between scanner and parser. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ namespace yy { template T ParserDriver::makeBase10(std::string number) { std::string exponent = ""; unsigned long i = 0; /* remove all underscores */ i = number.find('_', 0); while (i != std::string::npos) { number.erase(i, 1); i = number.find('_', 0); } /* check for exponent */ i = number.find_first_of("eE", 0); if (i != std::string::npos) { exponent = number.substr(i); /* remove exponent from number */ number = number.substr(0, i); } return ParserDriver::makeNumberFromParts(number, exponent, 10); } template T ParserDriver::makeBased(std::string number) throw(std::invalid_argument) { std::string exponent = ""; T num; unsigned long j = 0; char base = 10; /* remove all underscores */ j = number.find('_', 0); while (j != std::string::npos) { number.erase(j, 1); j = number.find('_', 0); } /* base specifier present? */ j = number.find('#', 0); if (j != std::string::npos) { std::string baseS = number.substr(0, j); base = static_cast(ParserDriver::makeLong(baseS, 10)); /* remove basespecifier + '#' */ number = number.substr(j + 1); j = number.find('#', 0); exponent = number.substr(j + 1); /* remove exponent */ number.erase(j); } else { throw std::invalid_argument("Number w.o. base specifier: " + number); } num = ParserDriver::makeNumberFromParts(number, exponent, base); return num; } template T ParserDriver::makeNumberFromParts(std::string& val, std::string& exponent, unsigned char base) { unsigned long i; long exp = 0; T result; /* 1. convert exponent */ /* leading E? -> remove it. */ if (exponent[0] == 'E' || exponent[0] == 'e') { exponent = exponent.substr(1); } exp = ParserDriver::makeLong(exponent, 10); /* 2. check for decimal point in val */ i = val.find('.'); if (i != std::string::npos) { /* remove . */ val.erase(i, 1); /* shift exponent by number of digits after . */ exp -= val.length() - i; } /* convert number */ result = static_cast(ParserDriver::makeLong(val, base)); /* 3. adjust by exponent */ /* FIXME sistpoty: range check! */ while (0 < exp) { result *= base; exp--; } while (exp < 0) { result /= base; exp++; } return result; } template void ParserDriver::registerSymbolDecls( const T *symbols, enum ast::symType type ) { if (symbols == NULL) { return; } for (typename T::const_iterator i = symbols->begin(); i != symbols->end(); i++) { this->symbolTable.registerSymbol(type, **i); } } }; /* namespace yy */ fauhdlc-20130704/frontend/newparser/FAUhdlScanner.hpp0000664000175000017500000000375411137610234021764 0ustar potyrapotyra/* $Id: FAUhdlScanner.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FAUHDLSCANNER_HPP_INCLUDED #define __FAUHDLSCANNER_HPP_INCLUDED /* make sure that yyFlexLexer will not get declared more than once */ #undef yyFlexLexer #include #include namespace yy { /** custom lexer class with a overloaded yylex function */ class FAUhdlScanner : public yyFlexLexer { public: // arg_yyin and arg_yyout default to the cin and cout, but we // only make that assignment when initializing in yylex(). FAUhdlScanner( FLEX_STD istream* arg_yyin = 0, FLEX_STD ostream* arg_yyout = 0 ) : yyFlexLexer(arg_yyin, arg_yyout), bracesCtr(0), isAssociation(false), backup(std::string()), scannedForAssociation(false) {} virtual ~FAUhdlScanner() {} /* defined from flex via mangling in ParserDriver.hpp for *this* * class */ virtual FAUhdlParser::token_type yylex( yy::FAUhdlParser::semantic_type* yylval, FAUhdlParser::location_type* yylloc, ParserDriver& driver ); private: /** unput all characters stored in backup */ void putBack(void) { for (std::string::reverse_iterator i = this->backup.rbegin(); i != this->backup.rend(); i++) { /* evil: copied definition of macro unput */ this->yyunput(*i, yytext); } } /** reset bracesCtr, isAssociation and backup */ void reset(void) { this->bracesCtr = 0; this->isAssociation = false; this->backup = ""; } /** braces counter (e.g. association list checking ) */ int bracesCtr; /** is an association? */ bool isAssociation; /** backup stack for lookahead scanning. */ std::string backup; /** already scanned for an association? */ bool scannedForAssociation; }; } #endif /* __FAUHDLSCANNER_HPP_INCLUDED */ fauhdlc-20130704/frontend/newparser/ParserDriver.cpp0000664000175000017500000002254612152355514021757 0ustar potyrapotyra/* $Id: ParserDriver.cpp 5117 2013-06-01 11:30:20Z potyra $ * * ParserDriver: glue class to driver between scanner and parser. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/newparser/ParserDriver.hpp" #include "frontend/newparser/FAUhdlScanner.hpp" #include #include #include #include #include #include #include #include "frontend/reporting/SyntaxError.hpp" #include "frontend/ast/NodeFactory.hpp" #include "util/MiscUtil.hpp" #include "frontend/ast/Callable.hpp" #include "frontend/misc/NameLookup.hpp" #include "frontend/reporting/UndefinedSymbol.hpp" #include "frontend/reporting/ErrorRegistry.hpp" namespace yy { ParserDriver::ParserDriver( ast::SymbolTable& symTab ) : scanner(NULL), topNode(new ast::LibraryList()), currentLibrary(NULL), symbolTable(symTab), nameLookup(*new ast::NameLookup(symTab)), lookupIdentifiers(true), label(NULL), currentFile(NULL), currentLoc(NULL) { } ParserDriver::~ParserDriver() { delete this->scanner; if (this->topNode) { util::MiscUtil::terminate(this->topNode); } delete &this->nameLookup; } int ParserDriver::yylex(FAUhdlParser::semantic_type* yylval, FAUhdlParser::location_type* yylloc) { this->currentLoc = yylloc; FAUhdlParser::token_type token = this->scanner->yylex(yylval, yylloc, *this); /* forward to lexer */ return token; } void ParserDriver::error(const FAUhdlParser::location_type& l, const std::string& msg) throw(SyntaxError) { std::stringstream stream; stream << "ERROR> "; if (this->currentFile) { stream << *this->currentFile << ":"; } stream << l.begin.line << ": Parse error: " << msg << std::endl; std::string *emsg = new std::string(); *emsg = stream.str(); SyntaxError err = SyntaxError(*emsg); throw err; } void ParserDriver::parse(const std::string& filename, const char* libName) throw(std::runtime_error, SyntaxError, ast::CompileError) { std::ifstream inStream; // open file inStream.open(filename.c_str(), std::ifstream::in); if (! inStream.good()) { inStream.close(); throw std::runtime_error("Failed to open file <" + filename + ">"); } // set up scanner this->scanner = new FAUhdlScanner(&inStream, &std::cout); FAUhdlParser *parser = new FAUhdlParser(*this); this->currentFile = new std::string(filename); this->currentLibrary = this->topNode->enterLibrary(libName); // enter library region this->symbolTable.pushLibrary(*(this->currentLibrary)); // push new region that will be the region of the first // design unit (and will get pop'd from within the parser) this->symbolTable.pushNewRegion(); // parse stuff parser->parse(); // close stream again inStream.close(); this->currentFile = NULL; // leave anonymous region that would contain the next design_unit // again this->symbolTable.popRegion(); // leave library region again this->symbolTable.popRegion(); delete parser; } void ParserDriver::toLower(std::string& mixed) { std::transform(mixed.begin(), mixed.end(), mixed.begin(), static_cast(std::tolower)); } long ParserDriver::makeLong(const std::string& intval, unsigned char base) throw(std::invalid_argument, std::out_of_range) { long result = 0; unsigned char basemul = 1; unsigned int i=0; char c; int digitValue; bool negative = false; if (intval[i] == '-' || intval[i] == '+') { if (intval[i] == '-') { negative = true; } i++; } for (; i < intval.length(); i++) { c = intval[i]; digitValue = ParserDriver::getDigitValue(c); if (digitValue == -1) { throw std::invalid_argument( "not a correct parameter " " number: " + intval); } if (base < digitValue) { throw std::out_of_range( "digit in greater than base " " number: " + intval); } result *= basemul; result += digitValue; basemul = base; } if (negative) { return -result; } return result; } std::string* ParserDriver::removeQuotes(std::string s) { size_t i; /* surrounding quotes */ s.erase(0, 1); s.erase(s.length() - 1, 1); /* replace all "" with " */ i = s.find("\"\"", 0); while (i != std::string::npos) { s.erase(i, 1); i = s.find("\"\"", i + 1); } return new std::string(s); } std::string* ParserDriver::makeBitString(std::string s) throw(std::out_of_range) { char spec = s[0]; if (spec == 'X' || spec == 'x') { return ParserDriver::makeHexBitString(s); } else if (spec == 'o' || spec == 'O') { return ParserDriver::makeOctBitString(s); } assert(spec == 'b' || spec == 'B'); unsigned long i; i = s.find('_'); while (i != std::string::npos) { s.erase(i, 1); i = s.find('_'); } // spec && first " s.erase(0, 2); // last " s.erase(s.length() - 1, 1); return new std::string(s); } void ParserDriver::registerLibUnit(ast::LibUnit *unit) { assert(this->currentLibrary); this->currentLibrary->units.push_back(unit); } FAUhdlParser::token_type ParserDriver::getTokenForId( const char *id, ast::NodeFactory::Identifier *&semanticValue, const FAUhdlParser::location_type &loc ) const { std::string* s = new std::string(id); ParserDriver::toLower(*s); std::list syms = std::list(); if (this->lookupIdentifiers) { syms = this->nameLookup.lookup(*s); // eventually register an error if (syms.empty()) { this->reportNameError(id, loc); } } semanticValue = new ast::NodeFactory::Identifier(s, syms); return ParserDriver::reduceSymbolToToken(semanticValue->candidates); } ast::SimpleName* ParserDriver::buildOperatorName( const char *op, const FAUhdlParser::location_type &loc ) const { ast::SimpleName* s = new ast::SimpleName(op, this->bl(loc)); // FIXME currently, this bypasses any selected scope by a // direct lookup in the SymbolTable. The current grammar // doesn't support expanded name as an operator, so it // doesn't matter. If the grammar is fixed, this should use // NameLookup instead. s->candidates = this->symbolTable.lookup(std::string(op)); if (s->candidates.empty()) { this->reportNameError(op, loc); } return s; } std::string* ParserDriver::makeHexBitString(std::string& s) { const char lookupHex[16][5] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; std::string *result = new std::string(); for (unsigned int i=2; i < s.length() - 1; i++) { int v = ParserDriver::getDigitValue(s[i]); if (v < 0) { continue; } /* should not happen. scanner's fault otherwise */ assert(v <= 0xF); result->append(lookupHex[static_cast(v)]); } return result; } std::string* ParserDriver::makeOctBitString(std::string& s) throw(std::out_of_range) { const char lookupOctal[8][4] = { "000", "001", "010", "011", "100", "101", "110", "111" }; std::string *result = new std::string(); /* x"3314_F_124_4" */ for (unsigned int i=2; i < s.length() - 1; i++) { int v = ParserDriver::getDigitValue(s[i]); if (v < 0) { continue; } if (v > 7) { delete result; throw std::out_of_range("digit out of range: " + s); } result->append(lookupOctal[static_cast(v)]); } return result; } int ParserDriver::getDigitValue(char c) { if (('0' <= c) && (c <= '9')) { return static_cast(c - '0'); } else if (('A' <= c) && (c <= 'Z')) { return static_cast(c - 'A' + 10); } else if (('a' <= c) && (c <= 'z')) { return static_cast(c - 'a' + 10); } return -1; } FAUhdlParser::token_type ParserDriver::reduceSymbolToToken(std::list candidates) { bool overloadPossible = false; // no candidates -> symbol was not found. unclassified identifier. if (candidates.empty()) { return FAUhdlParser::token::t_Identifier; } FAUhdlParser::token_type ret = FAUhdlParser::token::t_Identifier; switch(candidates.front()->type) { case ast::SYMBOL_PROCEDURE: ret = FAUhdlParser::token::ID_procedure; overloadPossible = true; break; case ast::SYMBOL_TYPE: ret = FAUhdlParser::token::ID_type; overloadPossible = true; break; case ast::SYMBOL_FUNCTION: ret = FAUhdlParser::token::ID_function; overloadPossible = true; break; case ast::SYMBOL_ALL: assert(false); default: ret = FAUhdlParser::token::t_Identifier; break; } if (candidates.size() == 1) { return ret; } /* more than one candidate: all should be of same type, otherwise * s.th. is wrong, at least if not of an overloadable type. * (FIXME: enum literal == function, * procedure vs. function (necessary?) */ for (std::list::const_iterator i = candidates.begin(); i != candidates.end(); i++) { switch((*i)->type) { case ast::SYMBOL_PROCEDURE: assert(overloadPossible); break; case ast::SYMBOL_FUNCTION: assert(ret == FAUhdlParser::token::ID_function); break; default: assert(ret == FAUhdlParser::token::t_Identifier); break; } } return ret; } void ParserDriver::reportNameError( const char *id, const FAUhdlParser::location_type &loc ) const { assert(this->lookupIdentifiers); ast::UndefinedSymbol *e = new ast::UndefinedSymbol( std::string(id), this->bl(loc)); ast::ErrorRegistry::addError(e); } }; /* namespace yy */ fauhdlc-20130704/frontend/reporting/0000775000175000017500000000000012165333076016640 5ustar potyrapotyrafauhdlc-20130704/frontend/reporting/TypeError.cpp0000664000175000017500000000154111137610234021270 0ustar potyrapotyra/* $Id: TypeError.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/reporting/TypeError.hpp" namespace ast { TypeError::TypeError( const AstNode &node, const TypeDeclaration &decl, std::string msg ) : CompileError(node, msg), typeName(*decl.name), declLoc(decl.location) { assert(decl.name != NULL); } void TypeError::put(std::ostream& stream) const { stream << this->location << ": " << this->message << " (type: " << this->typeName << ", declared at " << this->declLoc << ")" << std::endl; } }; /* namespace ast */ fauhdlc-20130704/frontend/reporting/CompileError.hpp0000664000175000017500000000315011137610234021742 0ustar potyrapotyra/* $Id: CompileError.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __COMPILE_ERROR_HPP_INCLUDED #define __COMPILE_ERROR_HPP_INCLUDED #include #include #include "frontend/ast/AstNode.hpp" namespace ast { //! base class for all Compile errors/warnings. class CompileError { public: //! c'tor /** @param node AstNode which contains the error. * @param msg error message. */ CompileError( const AstNode &node, std::string msg ) : location(node.location), message(msg) {} //! alternate c'tor /** @param loc location of the error * @param msg error message */ CompileError( Location loc, std::string msg ) : location(loc), message(msg) {} //! dummy d'tor virtual ~CompileError() {} //! write error to stream. /** @param stream write the compile error to this stream. */ virtual void put(std::ostream &stream) const; protected: /** location of the error */ Location location; /** error message */ std::string message; }; /** overload << operator for convenience. * @param stream stream where the error should be written to. * @param err CompileError that should be put to stream * @return stream to which the error was written to. */ std::ostream& operator<<(std::ostream& stream, const CompileError& err); }; /* namespace ast */ #endif /* __COMPILE_ERROR_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/TypeMismatch.cpp0000664000175000017500000000207411137610234021746 0ustar potyrapotyra/* $Id: TypeMismatch.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/reporting/TypeMismatch.hpp" namespace ast { TypeMismatch::TypeMismatch( const AstNode &ambigousNode, std::list possibleTypes, std::string msg) : AmbiguousTypes(ambigousNode, possibleTypes, msg) { } void TypeMismatch::put(std::ostream &stream) const { stream << this->location << ": " << " Type mismatch (" << this->message << ")" << std::endl; stream << "\tPossible types would be: " << std::endl; for (std::list< std::pair >::const_iterator i = this->typeNames.begin(); i != this->typeNames.end(); i++) { stream << "\t\t" << (*i).first << " (defined at: " << (*i).second << ")" << std::endl; } } }; /* namespace ast */ fauhdlc-20130704/frontend/reporting/ErrorRegistry.hpp0000664000175000017500000000455411137610234022173 0ustar potyrapotyra/* $Id: ErrorRegistry.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ERROR_REGISTRY_HPP_INCLUDED #define __ERROR_REGISTRY_HPP_INCLUDED #include #include "frontend/reporting/CompileError.hpp" namespace ast { //! register errors or warnings /** register errors or warnings during a SemanticCheck. */ class ErrorRegistry { public: /** register an error * @param error error that should get registered. */ static void addError(CompileError *error); /** register a warning. * @param warning warning that should get registered. */ static void addWarning(CompileError *warning); /** register a potential error * @param error potential error */ static void addPotentialError(CompileError* error); /** clear all potential errors. */ static void rejectPotentials(void); /** move all potential to the error queue, which means that these * have indeed been errors. */ static void acceptPotentials(void); /** have any errors been reported yet? * @return true if errors have been reported. */ static bool hasErrors(void); /** have any warnings been reported yet? * @return true, if there were warnings. */ static bool hasWarnings(void); /** put all warnings to stream. * @param stream stream to which warnings should get put to. */ static void putWarnings(std::ostream &stream); /** put all errors to stream. * @param stream stream to which errors should get put to. */ static void putErrors(std::ostream &stream); /** release all reported errors and warnings and free memory. */ static void flushAll(void); /** treat Warnings as errors (-Werror). Must only be set if no * warnings have been registered yet. * @param val true, to treat Warnings as errors, false otherwise. */ static void setWerror(bool val); private: /** compile errors */ static std::list errors; /** compile warnings */ static std::list warnings; /** potential errors */ static std::list potentialErrors; /** -Werror set? */ static bool werror; }; }; /* namespace ast */ #endif /* __ERROR_REGISTRY_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/DuplicateName.hpp0000664000175000017500000000235711137610234022063 0ustar potyrapotyra/* $Id: DuplicateName.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DUPLICATE_NAME_HPP_INCLUDED #define __DUPLICATE_NAME_HPP_INCLUDED #include "frontend/reporting/CompileError.hpp" namespace ast { //! name was declared more than once. /** A given name was declared already in the current scope. */ class DuplicateName : public CompileError { public: //! c'tor /** @param dupNode node where a symbol gets redefined. * @param referring previous definition of that name. * @param dName name of errorenous node. */ DuplicateName( const AstNode &dupNode, const AstNode &referring, std::string dName ); //! write error to stream. /** @param stream write the compile error to this stream. */ virtual void put(std::ostream& stream) const; protected: /** Location of previous declaration. */ const Location firstLoc; /** name that was declared twice. */ std::string name; }; }; /* namespace ast */ #endif /* __DUPLICATE_NAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/TypeMismatch.hpp0000664000175000017500000000213211137610234021746 0ustar potyrapotyra/* $Id: TypeMismatch.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_MISMATCH_HPP_INCLUDED #define __TYPE_MISMATCH_HPP_INCLUDED #include "frontend/reporting/AmbiguousTypes.hpp" namespace ast { //! Types mismatch. /** FIXME: almost identical to AmbiguousTypes! */ class TypeMismatch : public AmbiguousTypes { public: //! c'tor /** @param ambigousNode node which resolves to ambigous types. * @param possibleTypes possible type declarations for this node. * @param msg message. */ TypeMismatch( const AstNode &ambigousNode, std::list possibleTypes, std::string msg); protected: /** output error to stream * @param stream stream to write error to. */ virtual void put(std::ostream &stream) const; }; }; /* namespace ast */ #endif /* __TYPE_MISMATCH_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/UndefinedSymbol.hpp0000664000175000017500000000217711502711043022433 0ustar potyrapotyra/* $Id: UndefinedSymbol.hpp 5085 2010-12-17 16:38:59Z potyra $ * UndefinedSymbol: error meaning that a symbol could not get looked up. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __UNDEFINED_SYMBOL_HPP_INCLUDED #define __UNDEFINED_SYMBOL_HPP_INCLUDED #include "frontend/reporting/CompileError.hpp" namespace ast { //! symbol lookup failed. class UndefinedSymbol : public CompileError { public: //! c'tor /** @param name name which cannot be resolved. * @param loc location of the undefined symbol. */ UndefinedSymbol( const std::string &name, const Location &loc ); //! write error to stream. /** @param stream write the compile error to this stream. */ virtual void put(std::ostream &stream) const; protected: /** name which couldn't be resolved */ std::string failedName; }; }; /* namespace ast */ #endif /* __UNDEFINED_SYMBOL_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/DuplicateName.cpp0000664000175000017500000000147411137610234022055 0ustar potyrapotyra/* $Id: DuplicateName.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/reporting/DuplicateName.hpp" namespace ast { DuplicateName::DuplicateName( const AstNode& dupNode, const AstNode& referring, std::string dName ) : CompileError(dupNode, ""), firstLoc(referring.location), name(dName) { } void DuplicateName::put(std::ostream& stream) const { stream << this->location << ": " << "Symbol <" << this->name << "> redefined. " << "First defined here: " << this->firstLoc; } }; /* namespace ast */ fauhdlc-20130704/frontend/reporting/ErrorRegistry.cpp0000664000175000017500000000501111137610234022153 0ustar potyrapotyra/* $Id: ErrorRegistry.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/reporting/ErrorRegistry.hpp" namespace ast { void ErrorRegistry::addError(CompileError *error) { errors.push_back(error); } void ErrorRegistry::addWarning(CompileError *warning) { if (ErrorRegistry::werror) { errors.push_back(warning); } else { warnings.push_back(warning); } } void ErrorRegistry::addPotentialError(CompileError *error) { potentialErrors.push_back(error); } void ErrorRegistry::rejectPotentials(void) { for (std::list::const_iterator i = ErrorRegistry::potentialErrors.begin(); i != ErrorRegistry::potentialErrors.end(); i++) { delete *i; } potentialErrors.clear(); } void ErrorRegistry::acceptPotentials(void) { for (std::list::const_iterator i = potentialErrors.begin(); i != potentialErrors.end(); i++) { errors.push_back(*i); } potentialErrors.clear(); } bool ErrorRegistry::hasErrors(void) { return not errors.empty(); } bool ErrorRegistry::hasWarnings(void) { return not warnings.empty(); } void ErrorRegistry::putWarnings(std::ostream &stream) { for (std::list::const_iterator i = warnings.begin(); i != warnings.end(); i++) { stream << "WARNING> " << **i << std::endl; } } void ErrorRegistry::putErrors(std::ostream &stream) { for (std::list::const_iterator i = errors.begin(); i != errors.end(); i++) { stream << "ERROR> " << **i << std::endl; } } void ErrorRegistry::flushAll(void) { ErrorRegistry::rejectPotentials(); for (std::list::iterator i = errors.begin(); i != errors.end(); i++) { delete *i; } for (std::list::iterator i = warnings.begin(); i != warnings.end(); i++) { delete *i; } warnings.clear(); errors.clear(); } void ErrorRegistry::setWerror(bool val) { assert(ErrorRegistry::warnings.empty()); ErrorRegistry::werror = true; } /* initialize/define statics */ std::list ErrorRegistry::errors = std::list(); std::list ErrorRegistry::warnings = std::list(); std::list ErrorRegistry::potentialErrors = std::list(); bool ErrorRegistry::werror = false; }; /* namespace ast */ fauhdlc-20130704/frontend/reporting/SyntaxError.hpp0000664000175000017500000000141611137610234021643 0ustar potyrapotyra/* $Id: SyntaxError.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SYNTAX_ERROR_HPP_INCLUDED #define __SYNTAX_ERROR_HPP_INCLUDED #include #include namespace yy { /** A syntax error during parsing. */ class SyntaxError : public std::runtime_error { public: //! dummy c'tor to forward to runtime_error /** @param msg error message */ SyntaxError(const std::string& msg) : runtime_error(msg) {} }; }; /* namespace yy */ #endif /* __SYNTAX_ERROR_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/TypeError.hpp0000664000175000017500000000222711137610234021277 0ustar potyrapotyra/* $Id: TypeError.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_ERROR_HPP_INCLUDED #define __TYPE_ERROR_HPP_INCLUDED #include "frontend/reporting/CompileError.hpp" #include "frontend/ast/TypeDeclaration.hpp" namespace ast { //! a type error was encountered. class TypeError : public CompileError { public: //! c'tor /** @param node AST node which contains the type error * @param declaration declaration of type * @param msg message to report. */ TypeError( const AstNode &node, const TypeDeclaration &decl, std::string msg ); //! write error to stream. /** @param stream write the compile error to this stream. */ virtual void put(std::ostream& stream) const; protected: //! name of declared type std::string typeName; //! location of declared type Location declLoc; }; }; /* namespace ast */ #endif /* __TYPE_ERROR_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/UndefinedSymbol.cpp0000664000175000017500000000157411502711043022426 0ustar potyrapotyra/* $Id: UndefinedSymbol.cpp 5085 2010-12-17 16:38:59Z potyra $ * UndefinedSymbol: error meaning that a symbol could not get looked up. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/reporting/UndefinedSymbol.hpp" #include "frontend/ast/SimpleName.hpp" namespace ast { /* FIXME new SimpleName */ UndefinedSymbol::UndefinedSymbol( const std::string &name, const Location &loc ) : CompileError(loc, ""), failedName(name) { } void UndefinedSymbol::put(std::ostream& stream) const { stream << this->location << ": Symbol" << " '" << this->failedName << "'"; stream << " undefined."; } }; /* namespace ast */ fauhdlc-20130704/frontend/reporting/AmbiguousTypes.hpp0000664000175000017500000000246011137610234022323 0ustar potyrapotyra/* $Id: AmbiguousTypes.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __AMBIGUOUS_TYPES_HPP_INCLUDED #define __AMBIGUOUS_TYPES_HPP_INCLUDED #include "frontend/reporting/CompileError.hpp" namespace ast { //! type resolution resulted in ambigous types /** Error class, if type resolution determined more than one possible * type for a complete context. */ class AmbiguousTypes : public CompileError { public: //! c'tor /** @param ambigousNode node which resolves to ambigous types. * @param possibleTypes possible type declarations for this node. * @param msg message. */ AmbiguousTypes( const AstNode &ambigousNode, std::list possibleTypes, std::string msg); protected: /** output error to stream * @param stream stream to write error to. */ virtual void put(std::ostream &stream) const; /** list of type names together with the source location. */ std::list< std::pair > typeNames; }; }; /* namespace ast */ #endif /* __AMBIGUOUS_TYPES_HPP_INCLUDED */ fauhdlc-20130704/frontend/reporting/CompileError.cpp0000664000175000017500000000122311137610234021734 0ustar potyrapotyra/* $Id: CompileError.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/reporting/CompileError.hpp" namespace ast { void CompileError::put(std::ostream &stream) const { stream << this->location << ": " << this->message; } std::ostream& operator<<(std::ostream &stream, const CompileError &err) { err.put(stream); return stream; } }; /* namespace ast */ fauhdlc-20130704/frontend/reporting/AmbiguousTypes.cpp0000664000175000017500000000261511137610234022320 0ustar potyrapotyra/* $Id: AmbiguousTypes.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/reporting/AmbiguousTypes.hpp" #include "frontend/ast/TypeDeclaration.hpp" namespace ast { AmbiguousTypes::AmbiguousTypes( const AstNode &ambigousNode, std::list possibleTypes, std::string msg ) : CompileError(ambigousNode, msg) { for (std::list::const_iterator i = possibleTypes.begin(); i != possibleTypes.end(); i++) { if ((*i)->name == NULL) { typeNames.push_back(make_pair( std::string(""), (*i)->location)); continue; } typeNames.push_back(make_pair(*(*i)->name, (*i)->location)); } } void AmbiguousTypes::put(std::ostream &stream) const { stream << this->location << ": " << "ambigous types (" << this->message << ")" << std::endl; stream << "\tPossible types are: " << std::endl; for (std::list< std::pair >::const_iterator i = this->typeNames.begin(); i != this->typeNames.end(); i++) { stream << "\t\t" << (*i).first << " (defined at: " << (*i).second << ")" << std::endl; } } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/0000775000175000017500000000000012165333075015415 5ustar potyrapotyrafauhdlc-20130704/frontend/ast/AssociationElement.hpp0000664000175000017500000000412311137610234021705 0ustar potyrapotyra/* $Id: AssociationElement.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ASSOCIATION_ELEMENT_HPP_INCLUDED #define __ASSOCIATION_ELEMENT_HPP_INCLUDED #include #include "frontend/ast/Expression.hpp" #include "frontend/ast/SimpleName.hpp" namespace ast { /** one VHDL AssociationElement */ class AssociationElement : public AstNode { public: //! c'tor /** @param formalPart formal part * @param actualPart actual part (or NULL, if open) * @param loc location of the AssociationElement. */ AssociationElement( Name *formalPart, Expression *actualPart, Location loc ) : AstNode(loc), formal(formalPart), actual(actualPart), pos(-1), hiddenFormal(NULL) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { if (this->formal != NULL) { stream << *this->formal << " => "; } if (this->actual != NULL) { stream << *this->actual; } else { stream << "(open)"; } } /** formal part (name) */ Name *formal; /** actual part or NULL if it's open. */ Expression *actual; /** position of the associaton, -1 means unset, 0 is first position */ int pos; /** optional name of the formal, in case storage space is needed * for an association */ SimpleName *hiddenFormal; protected: /** Destructor */ virtual ~AssociationElement() { util::MiscUtil::terminate(this->formal); util::MiscUtil::terminate(this->actual); } }; }; /* namespace ast */ #endif /* __ASSOCIATION_ELEMENT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/TypeDeclaration.hpp0000664000175000017500000000252711137610234021214 0ustar potyrapotyra/* $Id: TypeDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * TypeDeclaration: AST Class representing a type declaration. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_DECLARATION_HPP_INCLUDED #define __TYPE_DECLARATION_HPP_INCLUDED #include "frontend/ast/AttributableDeclaration.hpp" #include "frontend/ast/Location.hpp" #include "frontend/ast/Types.hpp" namespace ast { //! one generic VHDL type declaration. /** This class represents one VHDL type declaration. */ class TypeDeclaration : public AttributableDeclaration { public: //! c'tor /** @param declName name of the declared type. * @param loc location of the declaration. * @param base base type of this declaration. */ TypeDeclaration( std::string *declName, Location loc, enum BaseType base ) : AttributableDeclaration(declName, loc), baseType(base), isUniversal(false) {} /** the base type of this declared type. */ enum BaseType baseType; //! is this either universal_integer or universal_real? bool isUniversal; }; }; /* namespace ast */ #endif /* __TYPE_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Location.cpp0000664000175000017500000000134211137610234017662 0ustar potyrapotyra/* $Id: Location.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/Location.hpp" namespace ast { std::ostream& Location::put(std::ostream &out) const { if (this->filename != NULL) { out << *this->filename << ":" << this->line; } else { out << "BUILTIN [" << this->information << "]"; } return out; } std::ostream& operator <<(std::ostream& stream, const Location& loc) { return loc.put(stream); } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/CaseAlternative.hpp0000664000175000017500000000374211137610234021177 0ustar potyrapotyra/* $Id: CaseAlternative.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CASE_ALTERNATIVE_HPP_INCLUDED #define __CASE_ALTERNATIVE_HPP_INCLUDED #include "frontend/ast/AstNode.hpp" #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/Expression.hpp" namespace ast { /** one alternative for a case statement */ class CaseAlternative : public AstNode { public: //! c'tor /** @param choices List of expressions for this alternative. * @param thenList List of statements to do if choices is true. * @param loc location of the alternative. */ CaseAlternative( std::list* choices, std::list* thenList, Location loc ) : AstNode(loc), isVals(choices), thenStats(thenList) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { util::MiscUtil::listPut(this->isVals, stream, "| "); stream << " => "; util::MiscUtil::listPut(this->thenStats, stream, "; "); } /** evaluate this alternative, if the condition of the * case-statement is one of isVals */ std::list* isVals; /** sequential statements of this alternative */ std::list* thenStats; protected: /** Destructor */ virtual ~CaseAlternative() { util::MiscUtil::lterminate(isVals); util::MiscUtil::lterminate(thenStats); } }; }; #endif /* __CASE_ALTERNATIVE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ProcedureDeclaration.hpp0000664000175000017500000000315211137610234022216 0ustar potyrapotyra/* $Id: ProcedureDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PROCEDURE_DECLARATION_HPP_INCLUDED #define __PROCEDURE_DECLARATION_HPP_INCLUDED #include "frontend/ast/Callable.hpp" namespace ast { /** a VHDL procdure declaration */ class ProcedureDeclaration : public Callable { public: //! c'tor /** @param declName declared name of the function or procedure. * @param args interface of the function or procedure. * @param loc location of the procedure declaration. */ ProcedureDeclaration( std::string *declName, std::list *args, Location loc ) : Callable( declName, args, SubprogBody::PROG_KIND_PROCEDURE, loc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "PROCEDURE " << *this->name << '('; util::MiscUtil::listPut(this->arguments, stream, ", "); stream << ");"; } }; }; /* namespace ast */ #endif /* __PROCEDURE_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ConstReal.hpp0000664000175000017500000000271411137610234020015 0ustar potyrapotyra/* $Id: ConstReal.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONST_REAL_HPP_INCLUDED #define __CONST_REAL_HPP_INCLUDED #include "frontend/ast/Expression.hpp" #include "frontend/visitor/Visitor.hpp" #include "frontend/ast/Types.hpp" namespace ast { //! One constant real. /** This class represents once constant VHDL real. */ class ConstReal : public Expression { public: //! c'tor /** @param val value of the VHDL real. * @param loc location of the definition. * @param unit physical unit. */ ConstReal( universal_real val, Location loc ) : Expression(BASE_TYPE_REAL, loc), value(val) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->value; } /** Value of the real. */ universal_real value; }; }; /* namespace ast */ #endif /* __CONST_REAL_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/FunctionDeclaration.hpp0000664000175000017500000000600511502707332022055 0ustar potyrapotyra/* $Id: FunctionDeclaration.hpp 5084 2010-12-17 16:24:58Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FUNCTION_DECLARATION_HPP_INCLUDED #define __FUNCTION_DECLARATION_HPP_INCLUDED #include "frontend/ast/Callable.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/misc/BuiltinFunction.hpp" #include "frontend/visitor/GCBuiltins.hpp" namespace ast { /** declaration of a VHDL function */ class FunctionDeclaration : public Callable { public: //! c'tor /** @param declName name of the function. * @param args interface (arguments the function takes). * @param body corresponding SubprogBody, if any. * @param returnT return type identifier of the function. * @param pureFunc is this function declared as pure? * @param loc location of the FunctionDeclaration. */ FunctionDeclaration( std::string *declName, std::list *args, SubtypeIndication *returnT, bool pureFunc, Location loc ) : Callable(declName, args, SubprogBody::PROG_KIND_FUNCTION, loc), returnType(returnT), builtin(NULL), gcBuiltin(NULL), isPure(pureFunc), isBuiltin(false) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "FUNCTION " << *this->name << '('; util::MiscUtil::listPut(this->arguments, stream, ", "); stream << ") RETURN " << this->returnType << ';'; } /** return the name, that the intermediate code should use. * Overloaded from SymbolDeclaration, since the path name * wouldn't be right for builtins. */ virtual std::string getICName(void) const { if (this->isBuiltin) { assert(this->name != NULL); return *this->name; } // not a bultin, reuse SymbolDeclaration's impl. return SymbolDeclaration::getICName(); } /** return type of the function */ SubtypeIndication *returnType; /** builtin function for constant propagation or NULL if not a * builtin. */ BuiltinFunction *builtin; /** inline intermediate code generation class or NULL if not a * builtin */ GCBuiltins *gcBuiltin; /** is the function declared as pure */ bool isPure; /** is this a builtin function? */ bool isBuiltin; protected: /** Destructor */ virtual ~FunctionDeclaration() { util::MiscUtil::terminate(this->returnType); delete this->builtin; this->builtin = NULL; delete this->gcBuiltin; this->gcBuiltin = NULL; } }; }; #endif /* __FUNCTION_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/NextStat.hpp0000664000175000017500000000361311137610234017674 0ustar potyrapotyra/* $Id: NextStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NEXT_STAT_HPP_INCLUDED #define __NEXT_STAT_HPP_INCLUDED #include "frontend/ast/ConditionedStat.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/LoopStat.hpp" #include "frontend/ast/SimpleName.hpp" namespace ast { /** a vhdl next statement */ class NextStat : public ConditionedStat { public: //! c'tor /** @param optCond condition that must be met (optional). * @param optLabel label that identifies the referring loop * (optional). * @param loc location of the NextStat. */ NextStat( Expression *optCond, SimpleName *optLabel, Location loc ) : ConditionedStat(optCond, loc), loopLabel(optLabel), referredLoop(NULL) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "NEXT"; if (this->loopLabel) { stream << ' ' << this->loopLabel; } stream << ';'; } /** Identifier of enclosing loop */ SimpleName *loopLabel; /** loop statement being referred to. */ LoopStat *referredLoop; protected: /** Destructor */ virtual ~NextStat() { util::MiscUtil::terminate(loopLabel); //FIXME? util::MiscUtil::terminate(referredLoop); } }; }; /* namespace ast */ #endif /* __NEXT_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/IfStat.hpp0000664000175000017500000000417311137610234017316 0ustar potyrapotyra/* $Id: IfStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __IF_STAT_HPP_INCLUDED #define __IF_STAT_HPP_INCLUDED #include "frontend/ast/ConditionedStat.hpp" #include "frontend/ast/Expression.hpp" namespace ast { /** an if-then-else statement */ class IfStat : public ConditionedStat { public: //! c'tor /** @param cond condition that needs to be evaluated to boolean * @param thenList list of statements to be executed if cond is true * @param elseList list of statements to be executed if cond is not * met. * @param loc location of the declaration. */ IfStat( Expression *cond, std::list *thenList, std::list *elseList, Location loc ) : ConditionedStat(cond, loc), thenStats(thenList), elseStats(elseList) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "IF " << this->condition << " THEN "; util::MiscUtil::listPut(this->thenStats, stream, "; "); if (this->elseStats) { stream << " ELSE "; util::MiscUtil::listPut(this->elseStats, stream, "; "); } stream << " END IF;"; } /** sequential statements that are part of the then-clause */ std::list *thenStats; /** sequential statements that are part of the else-clause */ std::list *elseStats; protected: /** Destructor */ virtual ~IfStat() { util::MiscUtil::lterminate(thenStats); util::MiscUtil::lterminate(elseStats); } }; }; /* namespace ast */ #endif /* __IF_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Subscript.hpp0000664000175000017500000000352111137610234020076 0ustar potyrapotyra/* $Id: Subscript.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SUBSCRIPT_HPP_INCLUDED #define __SUBSCRIPT_HPP_INCLUDED #include #include "frontend/ast/Expression.hpp" namespace ast { //! subscript operation on an array. /** Array subscription by an index, which returns the element. * arraytype(index {, index} ) -> element of arraytype. */ class Subscript : public Expression { public: //! c'tor /** @param sourceArrayType an Expression which returns an array. * @param idc list of indices. * @param loc Location of the Subscript operation. */ Subscript( Expression *sourceArrayType, std::list *idc, Location loc ) : Expression(loc), source(sourceArrayType), indices(idc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->source << '('; util::MiscUtil::listPut(this->indices, stream, ", "); stream << ')'; } //! source of the subscript. Expression *source; //! list of indices std::list *indices; protected: /** Destructor */ virtual ~Subscript() { util::MiscUtil::terminate(this->source); util::MiscUtil::lterminate(this->indices); } }; }; /* namespace ast */ #endif /* __SUBSCRIPT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Others.hpp0000664000175000017500000000224011137610234017361 0ustar potyrapotyra/* $Id: Others.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __OTHERS_HPP_INCLUDED #define __OTHERS_HPP_INCLUDED #include "frontend/ast/Expression.hpp" namespace ast { //! VHDL others expression. /** a VHDL others expression. */ class Others : public Expression { public: //! c'tor /** @param loc location of the Others expression. */ Others(Location loc) : Expression(loc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "OTHERS"; } }; }; /* namespace ast */ #endif /* __OTHERS_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/DiscreteRange.hpp0000664000175000017500000000672011244523367020654 0ustar potyrapotyra/* $Id: DiscreteRange.hpp 4580 2009-08-24 14:43:03Z potyra $ * * DiscreteRange: AST node for a discrete range. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DISCRETE_RANGE_HPP_INCLUDED #define __DISCRETE_RANGE_HPP_INCLUDED #include "frontend/ast/Name.hpp" #include namespace ast { //! a VHDL discrete range. class DiscreteRange : public Expression { public: /** This is a VHDL direction, either up or down. */ enum Direction { /** downwards (downto) */ DIRECTION_DOWN = -1, /** upwards (to) */ DIRECTION_UP = 1, }; //! c'tor /** @param first first argument to DiscreteRange. * @param second second argument to DiscreteRange. * @param direct direction of the range. * @param loc location of the DiscreteRange. */ DiscreteRange( Expression *first, Expression *second, enum Direction direct, Location loc ) : Expression(loc), from(first), to(second), direction(direct), rangeName(NULL) {} //! alternate c'tor for range by subytpe indication /** @param si SubtypeIndication referring to a range constraint type. * @param loc location of the DiscreteRange. */ DiscreteRange( SubtypeIndication *si, Location loc); //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const; /** determine the size of the array. * @return size of the array */ universal_integer getArraySize(void) const; /** determine the lower bound of the array. * @return lower bound of the array. */ universal_integer getLowerBound(void) const; /** determine the upper bound of the array. * @return upper bound of the array. */ universal_integer getUpperBound(void) const; /** determine the left bound of the array. * @return left bound of the array. */ universal_integer getLeftBound(void) const; /** determine the right bound of the array. * @return right bound of the array. */ universal_integer getRightBound(void) const; /** determine the direction of the array. Mainly for convenience, * direction holds the same information. * @return direction of the array (-1 for downto, 1 for to). */ universal_integer getDirection(void) const { return this->direction; } /** from bound of the DiscreteRange */ Expression *from; /** to bound of the DiscreteRange */ Expression *to; /** direction of the range */ enum Direction direction; /** optional range by range_attribute_name or * Other members should get set when * evaluating the name */ Name *rangeName; protected: /** Destructor */ virtual ~DiscreteRange() { util::MiscUtil::terminate(from); util::MiscUtil::terminate(to); util::MiscUtil::terminate(rangeName); } private: /** set from and to via range by SubtypeIndication * @param si SubtypeIndication referring to a constraint type. */ void setFromAndTo(const SubtypeIndication *si) throw(std::runtime_error); }; }; /* namespace ast */ #endif /* __DISCRETE_RANGE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ConstArray.hpp0000664000175000017500000000430611137610234020207 0ustar potyrapotyra/* $Id: ConstArray.hpp 4323 2009-01-27 13:48:12Z potyra $ * * A constant array (with constant values), AST node. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONST_ARRAY_HPP_INCLUDED #define __CONST_ARRAY_HPP_INCLUDED #include "frontend/ast/ConstInteger.hpp" #include #include namespace ast { //! a constant array with constant elements. class ConstArray : public Expression { public: //! c'tor /** @param elements array elements. * @param loc Location of the array. */ ConstArray( std::vector *elems, Location loc ) : Expression(BASE_TYPE_ARRAY, loc), elements(elems) { assert(elems != NULL); } //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "ConstArray FIXME"; } /** Interprete the ConstArray as a string, regardless of the actual * type it has. Should be used only, if the array is known to refer * to a textual type. * @return string representation of the array. */ std::string unsafeMakeString(void) const { assert(this->elements != NULL); std::string ret = std::string(); for (std::vector::const_iterator i = this->elements->begin(); i != this->elements->end(); i++) { char c = static_cast((*i)->value); ret += c; } return ret; } std::vector *elements; protected: /** destructor */ virtual ~ConstArray() { for (std::vector::iterator i = this->elements->begin(); i != this->elements->end(); i++) { util::MiscUtil::terminate(*i); } delete elements; } }; }; /* namespace ast */ #endif /* __CONST_ARRAY_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/CondalSigAssign.hpp0000664000175000017500000000463211137610234021134 0ustar potyrapotyra/* $Id: CondalSigAssign.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONDAL_SIG_ASSIGN_HPP_INCLUDED #define __CONDAL_SIG_ASSIGN_HPP_INCLUDED #include "frontend/ast/ConcurrentStat.hpp" #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/Name.hpp" namespace ast { //! A concurrent condal signal assign statement. /** This class represents a concurent condal signal assign statement or * a concurrent selected signal assign statement. * It can be assumed, that the correct if/case-statements have been * produced, which reflect the concurrent statement. * * @TODO options and guarded, whereas guarded needs symbol analysis * before it can be transformed into guard statements. */ class CondalSigAssign : public ConcurrentStat { public: //! c'tor /** @param trg target of the signal assignment. * @param assignTree the sequential statements that reflect * the semantics of the CondalSigAssign. Should be either * an SigAssignStat or a probably nested IfStat with * SigAssignStats as it's actions. * @param loc location of the assign symbol. */ CondalSigAssign( Name* trg, SeqStat* assignTree, Location loc ) : ConcurrentStat(loc), target(trg), assignStat(assignTree) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->target << " <= " << this->assignStat << ';'; } /** target of the signal assignment */ Expression* target; /** Either an IfStat or a SigAssignStat. The signal assignment * should get sequentialized during parsing already. */ SeqStat* assignStat; protected: /** Destructor */ virtual ~CondalSigAssign() { util::MiscUtil::terminate(target); util::MiscUtil::terminate(assignStat); } }; }; /* namespace ast */ #endif /* __CONDAL_SIG_ASSIGN_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SubtypeIndication.cpp0000664000175000017500000000412711305724462021561 0ustar potyrapotyra/* $Id: SubtypeIndication.cpp 4855 2009-12-03 12:04:02Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/SubtypeIndication.hpp" #include #include "frontend/misc/Symbol.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" namespace ast { SubtypeIndication::SubtypeIndication( Name *typeMark, Location loc ) : TypeDeclaration(NULL, loc, BASE_TYPE_UNSET), typeName(typeMark), constraint(NULL), indexConstraint(NULL), resolutionFunction(NULL), declaration(NULL) { if (typeMark && typeMark->candidates.size() == 1) { Symbol *sym = typeMark->candidates.front(); this->declaration = dynamic_cast( &sym->declaration); assert(this->declaration); this->baseType = this->declaration->baseType; } } SubtypeIndication::SubtypeIndication( const TypeDeclaration *byType, Location loc ) : TypeDeclaration(NULL, loc, byType->baseType), typeName(NULL), constraint(NULL), indexConstraint(NULL), resolutionFunction(NULL), declaration(byType) { } std::string * SubtypeIndication::getResolver(void) const { if (this->resolutionFunction == NULL) { const SubtypeIndication *parent = dynamic_cast( this->declaration); if (parent == NULL) { /* check for array types */ const UnconstrainedArrayType *ua = dynamic_cast( this->declaration); if (ua == NULL) { return NULL; } const SubtypeIndication *si = dynamic_cast( ua->elementType); if (si != NULL) { return si->getResolver(); } /* can records be resolved? */ return NULL; } return parent->getResolver(); } if (this->resolutionFunction->candidates.size() != 1) { assert(false); return NULL; } return new std::string(this->resolutionFunction->getName()); } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/RangeConstraintType.hpp0000664000175000017500000000340511137610234022064 0ustar potyrapotyra/* $Id: RangeConstraintType.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RANGE_CONSTRAINT_TYPE_HPP_INCLUDED #define __RANGE_CONSTRAINT_TYPE_HPP_INCLUDED #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/ast/DiscreteRange.hpp" namespace ast { //! one range constraint type. /** This class represents one VHDL range constraint type. */ class RangeConstraintType : public TypeDeclaration { public: //! c'tor /** @param declName name of the declared type. * @param range range constraint. * @param loc location of the declaration. */ RangeConstraintType( std::string *declName, DiscreteRange *range, Location loc ) : TypeDeclaration(declName, loc, BASE_TYPE_UNSET), constraint(range) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name != NULL); stream << "TYPE " << *this->name << ' ' << this->constraint; } /** the restriction */ DiscreteRange *constraint; protected: /** Destructor */ virtual ~RangeConstraintType() { util::MiscUtil::terminate(constraint); } }; }; /* namespace ast */ #endif /* __RANGE_CONSTRAINT_TYPE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SubprogBody.hpp0000664000175000017500000000376311137610234020367 0ustar potyrapotyra/* $Id: SubprogBody.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SUBPROG_BODY_HPP_INCLUDED #define __SUBPROG_BODY_HPP_INCLUDED #include #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/SeqStat.hpp" namespace ast { //! definition of a VHDL procedure or function. /** This class represents a VHDL function or procedure * body. */ class SubprogBody : public AstNode { public: /** kind of subprog body */ enum ProgKind { PROG_KIND_UNKNOWN, /**< unspecifed */ PROG_KIND_FUNCTION, /**< it's a function */ PROG_KIND_PROCEDURE /**< it's a procedure */ }; //! c'tor /** @param localDefs local definitions. * @param seqS sequential stat of the subprogram. * @param loc location of the definition. */ SubprogBody( std::list *localDefs, std::list *seqS, Location loc ) : AstNode(loc), seqStats(seqS), declarations(localDefs) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "suprogram body"; } /** sequential statements */ std::list *seqStats; /** declarations */ std::list *declarations; protected: /** Destructor */ virtual ~SubprogBody() { util::MiscUtil::lterminate(seqStats); util::MiscUtil::lterminate(declarations); } }; }; /* namespace ast */ #endif /* __SUBPROG_BODY_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/PhysicalType.hpp0000664000175000017500000000371611137610234020544 0ustar potyrapotyra/* $Id: PhysicalType.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PHYSICAL_TYPE_HPP_INCLUDED #define __PHYSICAL_TYPE_HPP_INCLUDED #include #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/ast/DiscreteRange.hpp" namespace ast { //! VHDL physical type definition. /** This class represents one VHDL physical type definition. */ class PhysicalType : public TypeDeclaration { public: //! c'tor /** @param declName name of the declared type. * @param constraint range constrained of the type. * @param assocUnits list of associated units * (primary + secondaries). * @param loc location of the declaration. */ PhysicalType( std::string *declName, DiscreteRange *range, std::list *assocUnits, Location loc ); //! Accept a Visitor. // /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "Physical Type " << *this->name; if (this->constraint) { stream << ' ' << this->constraint; } } /** range constraint of the type */ DiscreteRange *constraint; /** List of registered units (primary unit first) */ std::list *units; protected: /** Destructor */ virtual ~PhysicalType(); }; }; /* namespace ast */ #endif /* __PHYSICAL_TYPE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/NullStat.hpp0000664000175000017500000000234511137610234017671 0ustar potyrapotyra/* $Id: NullStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NULL_STAT_HPP_INCLUDED #define __NULL_STAT_HPP_INCLUDED #include "frontend/ast/SeqStat.hpp" #include "frontend/visitor/Visitor.hpp" namespace ast { //! VHDL null statement. /** This class represents a VHDL null statement, which is a noop. */ class NullStat : public SeqStat { public: //! c'tor /** @param loc location of the NullStat. */ NullStat(Location loc) : SeqStat(loc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "NULL;"; } }; }; /* namespace ast */ #endif /* __NULL_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ReturnStat.hpp0000664000175000017500000000331511137610234020234 0ustar potyrapotyra/* $Id: ReturnStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RETURN_STAT_HPP_INCLUDED #define __RETURN_STAT_HPP_INCLUDED #include "frontend/ast/Expression.hpp" #include "frontend/ast/SeqStat.hpp" namespace ast { //! VHDL return statement. /** a VHDL return statement */ class ReturnStat : public SeqStat { public: //! c'tor /** @param optExpr expression that determines the return value * @param loc location of the return statement. */ ReturnStat( Expression *optExpr, Location loc ) : SeqStat(loc), result(optExpr), enclosingSubprog(NULL) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "RETURN"; if (this->result) { stream << ' ' << this->result; } stream << ';'; } /** result that should get returned (optional) */ Expression *result; /** enclosing subprogram declaration */ Callable *enclosingSubprog; protected: /** Destructor */ virtual ~ReturnStat() { util::MiscUtil::terminate(result); util::MiscUtil::terminate(enclosingSubprog); } }; }; /* namespace ast */ #endif /* __RETURN_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AstNode.cpp0000664000175000017500000000127311137610234017452 0ustar potyrapotyra/* $Id: AstNode.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/AstNode.hpp" namespace ast { std::ostream& operator<<(std::ostream &stream, const AstNode &node) { node.put(stream); return stream; } std::ostream& operator<<(std::ostream &stream, const AstNode *node) { if (node != NULL) { node->put(stream); } else { stream << "(null)"; } return stream; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/SubtypeIndication.hpp0000664000175000017500000000621511305512631021557 0ustar potyrapotyra/* $Id: SubtypeIndication.hpp 4849 2009-12-02 16:28:09Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SUBTYPE_INDICATION_HPP_INCLUDED #define __SUBTYPE_INDICATION_HPP_INCLUDED #include "frontend/ast/Name.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/misc/Symbol.hpp" namespace ast { //! any Name referring to a type or subtype. /** This class contains the superset of Names referring to a type or * subtype, eventually with a unique constraint and/or a * Resolution function. */ class SubtypeIndication : public TypeDeclaration { public: //! c'tor /** @param typeMark Name referring to the type or subtype * @param loc location of the type name. */ SubtypeIndication(Name *typeMark, Location loc); //! alternate c'tor /** Construct a SubtypeIndication directly by a given type. * @param byType type that the SubtypeIndication refers to. * @param loc Location of the SubtypeIndication. */ SubtypeIndication(const TypeDeclaration *byType, Location loc); //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "Subtype "; if (this->typeName != NULL) { stream << this->typeName; } else { stream << "(unnammed)"; } assert(this->declaration != NULL); stream << " : "; if (this->declaration->name != NULL) { stream << *this->declaration->name; } else { stream << "(unnamed)"; } if (this->constraint) { stream << ' ' << this->constraint; } if (this->indexConstraint) { stream << " ("; util::MiscUtil::listPut(this->indexConstraint, stream, ", "); stream << ')'; } if (this->resolutionFunction) { stream << " resolved by " << this->resolutionFunction; } } /** Name referring to the type or subtype */ Name *typeName; /** optional range constraint */ DiscreteRange *constraint; /** optional index constraint */ std::list *indexConstraint; /** optional additional resolution function. */ Name *resolutionFunction; /** the referred to type declaration, not reference counted! */ const TypeDeclaration *declaration; /** Return the resolution function of the subtype indication, if any. * @return resolution function or null. Caller should free the return * value. */ std::string *getResolver(void) const; protected: /** Destructor */ virtual ~SubtypeIndication() { util::MiscUtil::terminate(typeName); util::MiscUtil::terminate(constraint); util::MiscUtil::terminate(resolutionFunction); } }; }; /* namespace ast */ #endif /*__SUBTYPE_INDICATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Location.hpp0000664000175000017500000000330311137610234017666 0ustar potyrapotyra/* $Id: Location.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LOCATION_HPP_INCLUDED #define __LOCATION_HPP_INCLUDED #include #include namespace ast { /** location of a definiton. */ class Location { public: //! c'tor /** @param lineNo line number in the file. * @param filenm name of the file. */ Location( unsigned int lineNo, const std::string *filenm ) : line(lineNo), filename(filenm), information(NULL) {} //! alternate c'tor for builtins. /** @param info additional information. */ Location(const char *info) : line(0), filename(NULL), information(info) {} //! dummy d'tor virtual ~Location() {} /** Output the location to a stream. * @param out stream to which the location should get written to. * @return stream on which the location was written to. */ std::ostream& put(std::ostream &out) const; /** line in the file */ unsigned int line; /** filename */ const std::string *filename; /** other information */ const char *information; }; /** overloaded operator to conveniently output locations. * @param stream stream to which a location should get written to. * @param loc location reference that should get written to the stream. * @return modified stream */ std::ostream& operator <<(std::ostream& stream, const Location& loc); }; /* namespace ast */ #endif /* __LOCATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/WaveFormElem.hpp0000664000175000017500000000334411137610234020454 0ustar potyrapotyra/* $Id: WaveFormElem.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __WAVE_FORM_ELEM_HPP_INCLUDED #define __WAVE_FORM_ELEM_HPP_INCLUDED #include "frontend/ast/AstNode.hpp" #include "frontend/ast/Expression.hpp" namespace ast { //! a VHDL waveform element. /** This class represents a VHDL WaveForm Element. */ class WaveFormElem : public AstNode { public: //! c'tor /** @param val value of the WaveFormElem. * @param tdelay delay of the value. * @param loc Location of the WaveFormElement. */ WaveFormElem( Expression *val, Expression *tdelay, Location loc ) : AstNode(loc), value(val), delay(tdelay) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->value; if (this->delay) { stream << " AFTER " << this->delay; } } /** value of the WaveFormElem */ Expression *value; /** delay of the WaveFormElem */ Expression *delay; protected: /** Destructor */ virtual ~WaveFormElem() { util::MiscUtil::terminate(value); util::MiscUtil::terminate(delay); } }; }; /* namespace ast */ #endif /* __WAVE_FORM_ELEM_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/WaitStat.hpp0000664000175000017500000000374111137610234017664 0ustar potyrapotyra/* $Id: WaitStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __WAIT_STAT_HPP_INCLUDED #define __WAIT_STAT_HPP_INCLUDED #include #include "frontend/ast/ConditionedStat.hpp" #include "frontend/ast/Name.hpp" namespace ast { //! a VHDL wait statement. /** This class represents a VHDL wait statement. */ class WaitStat : public ConditionedStat { public: //! c'tor /** @param sens Sensitivity list of signals. * @param cond Condition to stop waiting. * @param time wait for max timeout. * @param loc location of the wait statement. */ WaitStat( std::list *sens, Expression *cond, Expression *time, Location loc ) : ConditionedStat(cond, loc), sensitivities(sens), timeout(time) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "WAIT"; if (this->sensitivities) { stream << " ON "; util::MiscUtil::listPut(this->sensitivities, stream, ", "); } if (this->timeout) { stream << " FOR " << this->timeout; } stream << ';'; } /** sensitivity list to wait on*/ std::list *sensitivities; /** wait maximal for timeout */ Expression *timeout; protected: /** Destructor */ virtual ~WaitStat() { util::MiscUtil::lterminate(sensitivities); util::MiscUtil::terminate(timeout); } }; }; /* namespace ast */ #endif /* __WAIT_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/PhysicalTypeUnit.hpp0000664000175000017500000000437711137610234021410 0ustar potyrapotyra/* $Id: PhysicalTypeUnit.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PHYSICAL_TYPE_UNIT_HPP_INCLUDED #define __PHYSICAL_TYPE_UNIT_HPP_INCLUDED #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/Types.hpp" namespace ast { //! Unit of a physical type. (primary/secondary unit) /** This class represents a primary or secondary unit declaration of * a PhysicalType. * It's no direct type declaration, but declares a symbol. */ class PhysicalTypeUnit : public SymbolDeclaration { public: //! c'tor /** @param declName name of the declaration. * @param unit phyiscal unit that is being referred to with factor. * @param loc location of the declaration. */ PhysicalTypeUnit( std::string *declName, ConstInteger *unit, Location loc ) : SymbolDeclaration(declName, loc), physUnit(unit), parent(NULL) { if (unit != NULL) { factor = unit->value; } else { factor = 1; } } //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << *this->name; if (this->physUnit) { stream << " = " << this->physUnit; } } /** reference physical unit and factor. */ ConstInteger *physUnit; /** TypeDeclaration the unit belongs to * warning: not reference counted here due to cyclic nature. */ const PhysicalType *parent; /** factor of base units */ universal_integer factor; protected: /** Destructor */ virtual ~PhysicalTypeUnit() { util::MiscUtil::terminate(physUnit); } }; }; /* namespace ast */ #endif /* __SECONDARY_TYPE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Slice.hpp0000664000175000017500000000313311137610234017156 0ustar potyrapotyra/* $Id: Slice.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SLICE_HPP_INCLUDED #define __SLICE_HPP_INCLUDED #include "frontend/ast/Expression.hpp" namespace ast { //! slice operation on an array type. /** array(bound1 [down]to bound2) -> array * Will create a slice of an array from bound1 to or downto bound2. * Returning type is the same array type but with different bounds. */ class Slice : public Expression { public: Slice( Expression *arrayTypeSource, DiscreteRange *dRange, Location loc ) : Expression(loc), source(arrayTypeSource), range(dRange) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->source << '(' << this->range << ')'; } //! source operand. Expression *source; //! slice range. DiscreteRange *range; protected: /** Destructor */ virtual ~Slice() { util::MiscUtil::terminate(source); util::MiscUtil::terminate(range); } }; }; /* namespace ast */ #endif /* __SLICE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AttributeDeclaration.hpp0000664000175000017500000000270411137610234022233 0ustar potyrapotyra/* $Id: AttributeDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * AtributeDeclaration: AST Class representing an attribute declaration. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ATTRIBUTE_DECLARATION_HPP_INCLUDED #define __ATTRIBUTE_DECLARATION_HPP_INCLUDED #include "frontend/ast/SymbolDeclaration.hpp" /* must use forward declaration of TypeDeclaration... otherwise circular */ namespace ast { //! one generic VHDL attribute declaration. class AttributeDeclaration : public SymbolDeclaration { public: AttributeDeclaration( std::string *declName, const TypeDeclaration *t, Location loc ) : SymbolDeclaration(declName, loc), type(t) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** type of the attribute */ const TypeDeclaration *type; /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const; }; }; /* namespace ast */ #endif /* __ATTRIBUTE_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ConstantDeclaration.hpp0000664000175000017500000000430011137610234022053 0ustar potyrapotyra/* $Id: ConstantDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONSTANT_DECLARATION_HPP_INCLUDED #define __CONSTANT_DECLARATION_HPP_INCLUDED #include "frontend/ast/ValDeclaration.hpp" #include "frontend/visitor/Visitor.hpp" #include "frontend/ast/Expression.hpp" namespace ast { //! A VHDL constant declaration. /** This class represents a declaration of a VHDL constant. * A constant must never be target of an assignment statement. * (it can change though, e.g. the loop parameter of an iteration scheme). */ class ConstantDeclaration : public ValDeclaration { public: /** c'tor * @param declName the declared name * @param varInit initializer Expression for the constant. * @param subtype subtype indication of the constant. * @param fValue has the constant a fixed value? * @param loc location of the ConstantDeclaration. */ ConstantDeclaration( std::string* declName, Expression* varInit, SubtypeIndication* subtype, bool fValue, Location loc ) : ValDeclaration(ValDeclaration::MODE_IN, declName, varInit, subtype, ValDeclaration::OBJ_CLASS_CONSTANT, loc), fixedValue(fValue) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name != NULL); stream << "CONSTANT " << *this->name << " : " << this->subtypeIndic; if (this->init != NULL) { stream << " := " << *this->init; } stream << ';'; } /** true, if the constant will always evaluate to the same value. */ bool fixedValue; }; }; /* namespace ast */ #endif /* __CONSTANT_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/PrefixedName.hpp0000664000175000017500000000216111137610234020466 0ustar potyrapotyra/* $Id: PrefixedName.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PREFIXED_NAME_HPP_INCLUDED #define __PREFIXED_NAME_HPP_INCLUDED #include "frontend/ast/Name.hpp" namespace ast { //! a name with an expression as a prefix. /** a name with an expression as a prefix. */ class PrefixedName : public Name { public: //! c'tor /** @param n identifier of the name * @param pre prefix of the name * @param cands candidate symbols * @param loc corresponding location */ PrefixedName( std::string *n, Expression *pre, std::list cands, Location loc ) : Name(n, cands, loc), prefix(pre) {} //! prefix expression of the name Expression *prefix; protected: //! d'tor virtual ~PrefixedName() { util::MiscUtil::terminate(this->prefix); } }; }; /* namespace ast */ #endif /* __PREFIXED_NAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/PhysicalType.cpp0000664000175000017500000000173711137610234020540 0ustar potyrapotyra/* $Id: PhysicalType.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/PhysicalType.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" namespace ast { PhysicalType::PhysicalType( std::string* declName, DiscreteRange* range, std::list* assocUnits, Location loc ) : TypeDeclaration(declName, loc, BASE_TYPE_INTEGER), constraint(range), units(assocUnits) { // set parent of each unit. for (std::list::iterator i = this->units->begin(); i != this->units->end(); i++) { (*i)->parent = this; } } PhysicalType::~PhysicalType() { util::MiscUtil::terminate(constraint); util::MiscUtil::lterminate(units); } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/Name.hpp0000664000175000017500000000367411502707332017013 0ustar potyrapotyra/* $Id: Name.hpp 5084 2010-12-17 16:24:58Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NAME_HPP_INCLUDED #define __NAME_HPP_INCLUDED #include #include #include #include "frontend/ast/Expression.hpp" namespace ast { class Symbol; //! base class for any VHDL name. class Name : public Expression { public: //! c'tor /** @param n string of the name * @param cands list with candidates of correlating symbols. * @param loc corresponding location */ Name( std::string *n, std::list cands, Location loc ) : Expression(loc), name(n), candidates(cands) {} /** actual name */ std::string *name; /** candidates symbols for this Name */ std::list candidates; //! return the declaration of the symbol /** This method will return the declaration of the symbol. The symbol * must hence be resolved to a unique name, otherwise this method * may not get called. * @return declaration of the simple name. */ SymbolDeclaration *getDeclaration(void) const; /** get the name of the definition. Will return a name, * that must be the same for each parse run of an identical * design hierarchy, and that must be unique within this * hierarchy. * * This function is a convenience only function (taking the * symbol's definition and call getICName() there and should * probably go away (FIXME). * * @throw std::logic_error, in case the name is not uniquely * resolved. * @return name of the definition. */ std::string getName(void) const throw(std::logic_error); protected: //! d'tor virtual ~Name() { delete this->name; } }; }; /* namespace ast */ #endif /* __NAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Aggregate.hpp0000664000175000017500000000321211137610234020003 0ustar potyrapotyra/* $Id: Aggregate.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __AGGREGATE_HPP_INCLUDED #define __AGGREGATE_HPP_INCLUDED #include #include "frontend/ast/Expression.hpp" #include "frontend/ast/ElementAssociation.hpp" namespace ast { //! VHDL aggregate /** This class represents an VHDL aggregate. */ class Aggregate : public Expression { public: //! c'tor /** @param assocs list of element associations. * @param loc location of the aggregate. */ Aggregate( std::list* assocs, Location loc ) : Expression(loc), associations(assocs) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "Aggregate ("; util::MiscUtil::listPut(this->associations, stream, ", "); stream << ")"; } /** list of elements associations. */ std::list *associations; protected: /** Destructor */ virtual ~Aggregate() { util::MiscUtil::lterminate(associations); } }; }; /* namespace ast */ #endif /* __AGGREGATE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/LibraryList.hpp0000664000175000017500000000375711137610234020373 0ustar potyrapotyra/* $Id: LibraryList.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LIBRARY_LIST_HPP_INCLUDED #define __LIBRARY_LIST_HPP_INCLUDED #include #include "frontend/ast/Library.hpp" namespace ast { //! Top node, a list of design libraries. /** This class is the hierarchical top node of each abstract syntax tree. * It represents a unique list of design libraries. * * @TODO make a distinction between resource libraries and the work library. */ class LibraryList : public AstNode { public: //! c'tor LibraryList(void) : AstNode( Location("library list")) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "LIST OF LIBRARIES... why do you want to know?"; } /** add a library with given name to the library list, * in case it doesn't exist yet. * * @param libname name of the library * @return either the library in question or a newly generated * one. */ Library* enterLibrary(const char* libname) { for (std::list::const_iterator i = this->libraries.begin(); i != this->libraries.end(); i++) { if ((*(*i)->name) == libname) { return *i; } } Library *n = new Library(new std::string(libname)); this->libraries.push_back(n); return n; } /** list of LibUnit */ std::list libraries; }; }; /* namespace ast */ #endif /* __LIBRARY_LIST_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/VarDeclaration.hpp0000664000175000017500000000364711137610234021027 0ustar potyrapotyra/* $Id: VarDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __VAR_DECLARATION_HPP_INCLUDED #define __VAR_DECLARATION_HPP_INCLUDED #include "frontend/ast/ValDeclaration.hpp" #include "frontend/visitor/Visitor.hpp" #include "frontend/ast/Expression.hpp" namespace ast { //! A VHDL variable declaration. /** This class represents a declaration of a VHDL variable. */ class VarDeclaration : public ValDeclaration { public: /** c'tor * @param accessMode mode of the Signal (in, out, inout). * @param declName the declared name * @param varInit initializer Expression for the variable. * @param subtype subtype indication of the variable. * @param loc Location of the declaration. */ VarDeclaration( enum ValDeclaration::Mode accessMode, std::string *declName, Expression *varInit, SubtypeIndication *subtype, Location loc ) : ValDeclaration(accessMode, declName, varInit, subtype, ValDeclaration::OBJ_CLASS_VARIABLE, loc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name != NULL); stream << "VARIABLE " << *this->name << " : " << this->subtypeIndic; if (this->init != NULL) { stream << " := " << *this->init; } stream << ';'; } }; }; /* namespace ast */ #endif /* __VAR_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SimpleName.cpp0000664000175000017500000000317211254460367020161 0ustar potyrapotyra/* $Id: SimpleName.cpp 4675 2009-09-17 16:16:55Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/SimpleName.hpp" #include #include "frontend/misc/Symbol.hpp" #include "frontend/ast/SignalDeclaration.hpp" namespace ast { bool SimpleName::isSignal(void) const { assert(this->candidates.size() >= 1); if (this->candidates.size() != 1) { // overloaded -> function or procedure return false; } switch (this->candidates.front()->type) { case SYMBOL_SIGNAL: case SYMBOL_PORT: return true; case SYMBOL_PARAMETER: { // might be a signal, check const SignalDeclaration *sig = dynamic_cast( &this->candidates.front()->declaration); if (sig != NULL) { return true; } break; } default: break; } return false; } bool SimpleName::operator==(const SimpleName &other) const { if ((*this->name) != (*other.name)) { return false; } // FIXME will that dereference pointers? if (this->prefixStrings != other.prefixStrings) { return false; } if (this->candidates.size() != other.candidates.size()) { return false; } std::list::const_iterator i = this->candidates.begin(); std::list::const_iterator j = other.candidates.begin(); for (; i != this->candidates.end(); i++, j++) { if ((*i)->type != (*j)->type) { return false; } } return true; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/LoopStat.hpp0000664000175000017500000000212411137610234017663 0ustar potyrapotyra/* $Id: LoopStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LOOP_STAT_HPP_INCLUDED #define __LOOP_STAT_HPP_INCLUDED #include #include "frontend/ast/SeqStat.hpp" namespace ast { /** generic class for loop statements */ class LoopStat : public SeqStat { public: //! c'tor /** @param lbl label of the loop * @param stats sequential statements enclosed by the loop * @param loc Location of the Loop statement. */ LoopStat( std::string *lbl, std::list *stats, Location loc ) : SeqStat(lbl, loc), loopStats(stats) {} /** sequential statements of the loop */ std::list *loopStats; protected: /** Destructor */ virtual ~LoopStat() { util::MiscUtil::lterminate(loopStats); } }; }; /* namespace ast */ #endif /* __LOOP_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ForLoopStat.hpp0000664000175000017500000000366011137610234020340 0ustar potyrapotyra/* $Id: ForLoopStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FOR_LOOP_STAT_HPP_INCLUDED #define __FOR_LOOP_STAT_HPP_INCLUDED #include "frontend/ast/LoopStat.hpp" #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/ConstantDeclaration.hpp" namespace ast { /** for loop statement */ class ForLoopStat : public LoopStat { public: //! c'tor /** @param lbl optional label of the loop. * @param stats sequential statements of the loop. * @param loopVar loop counter variable. * @param rng discrete range to iterate over. * @param loc location of the for statement. */ ForLoopStat( std::string *lbl, std::list *stats, ConstantDeclaration *loopVar, DiscreteRange *rng, Location loc ) : LoopStat(lbl, stats, loc), loopVariable(loopVar), range(rng) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "FOR " << this->loopVariable << " IN " << this->range << ';'; } /** loop counter variable */ ConstantDeclaration *loopVariable; /** discrete range that gets iterated over. */ DiscreteRange *range; protected: /** Destructor */ virtual ~ForLoopStat() { util::MiscUtil::terminate(loopVariable); util::MiscUtil::terminate(range); } }; }; /* namespace ast */ #endif /* __FOR_LOOP_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/TypeConversion.hpp0000664000175000017500000000366611137610234021121 0ustar potyrapotyra/* $Id: TypeConversion.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_CONVERSION_HPP_INCLUDED #define __TYPE_CONVERSION_HPP_INCLUDED #include "frontend/ast/Expression.hpp" #include "frontend/ast/TypeDeclaration.hpp" namespace ast { /** convert a source expression to a target type. * This class represents both explicit VHDL type conversions as well * as implicit type conversions, which type analysis will insert at * the places in question. */ class TypeConversion : public Expression { public: /** c'tor * @param src source expression * @param trg type to which source should get converted to. * @param loc Location of the type conversion in question. */ TypeConversion( Expression *src, const TypeDeclaration *trg, Location loc ) : Expression(loc), source(src), targetType(trg) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->targetType << '(' << this->source << ')'; } /** source Expression of the TypeConversion */ Expression *source; /** type to which source should get converted to. * doesn't get reference counted. */ const TypeDeclaration *targetType; protected: /** Destructor */ virtual ~TypeConversion() { util::MiscUtil::terminate(source); } }; }; /* namespace ast */ #endif /* __TYPE_CONVERSION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/VarAssignStat.hpp0000664000175000017500000000333711137610234020656 0ustar potyrapotyra/* $Id: VarAssignStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __VAR_ASSIGN_STAT_HPP_INCLUDED #define __VAR_ASSIGN_STAT_HPP_INCLUDED #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/Name.hpp" #include "frontend/ast/VarDeclaration.hpp" namespace ast { /** variable assign statement */ class VarAssignStat : public SeqStat { public: //! c'tor /** @param trg target of the VarAssignStat. * @param src source expression. * @param loc Location of the variable assign statement. */ VarAssignStat( Name *trg, Expression *src, Location loc ) : SeqStat(loc), target(trg), source(src) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->target << " := " << this->source << ';'; } /** target */ Expression *target; /** source that get's evaluated and assigned to target */ Expression *source; protected: /** Destructor */ virtual ~VarAssignStat() { util::MiscUtil::terminate(target); util::MiscUtil::terminate(source); } }; }; #endif /* __VAR_ASSIGN_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/EnumerationType.hpp0000664000175000017500000000363011243477217021263 0ustar potyrapotyra/* $Id: EnumerationType.hpp 4555 2009-08-21 11:01:35Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ENUMERATION_TYPE_HPP_INCLUDED #define __ENUMERATION_TYPE_HPP_INCLUDED #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/ast/FunctionDeclaration.hpp" namespace ast { //! one VHDL enumeration type. /** This class represents one VHDL enumeration type. */ class EnumerationType : public TypeDeclaration { public: //! c'tor /** @param declName name of the declared type. * @param elems declared enumeration elements. These are * Function declarations, which will be marked as * builtins and will return the value of the * EnumerationElement. * @param loc location of the declaration. */ EnumerationType( std::string* declName, std::list *elems, Location loc ) : TypeDeclaration(declName, loc, BASE_TYPE_ENUM), elements(elems) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "EnumerationType " << *this->name; } /** declared enumeration elements, i.e. the resulting identity * functions (builtins) that yield the enumeration value. */ std::list *elements; }; }; /* namespace ast */ #endif /* __ENUMERATION_TYPE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/NodeFactory.cpp0000664000175000017500000004551511243470602020342 0ustar potyrapotyra/* $Id: NodeFactory.cpp 4552 2009-08-21 10:05:54Z potyra $ * * NodeFactory: helper scripts for the Parser to create AST nodes, mainly * useful to keep lots of c++ code out of the parser. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include "frontend/ast/NodeFactory.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/VarDeclaration.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/WhileLoopStat.hpp" #include "frontend/ast/SigAssignStat.hpp" #include "frontend/ast/FunctionCall.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include "frontend/reporting/CompileError.hpp" #include "frontend/reporting/UndefinedSymbol.hpp" #include "frontend/misc/SymbolTable.hpp" #include "frontend/misc/NameLookup.hpp" #include "frontend/misc/BuiltinFunction.hpp" #include "frontend/ast/EnumerationType.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/visitor/ResolveTypes.hpp" #include "frontend/ast/UnconstrainedArrayType.hpp" namespace ast { struct NodeFactory::IfHelperS& NodeFactory::createNestedElseIfs( struct NodeFactory::IfHelperS* remainder, Expression* condition, std::list* thenStats, Location loc ) { struct NodeFactory::IfHelperS* ret = NULL; /* no parent elsif statements... create one */ if (remainder == NULL) { ret = new NodeFactory::IfHelperS(); ret->topstat = new IfStat(condition, thenStats, NULL, loc); ret->bottomElse = &(ret->topstat->elseStats); return *ret; } /* parent present. attach to bottom else */ IfStat *bottomIf = new IfStat(condition, thenStats, NULL, loc); std::list* l = new std::list(); l->push_back(bottomIf); *(remainder->bottomElse) = l; /* set old bottom else to new one */ remainder->bottomElse = &(bottomIf->elseStats); return *remainder; } IfStat& NodeFactory::createIfStat( Expression* condition, std::list* thenStats, struct NodeFactory::IfHelperS* elsIfs, std::list* elseStats, ast::Location loc ) { IfStat* ret = NULL; /* trivial case: no eslIfs */ if (elsIfs == NULL) { ret = new IfStat(condition, thenStats, elseStats, loc); return *ret; } /* remap elsIfs to nested if-else (part already done via elseIfs */ /* sanity checks for parser */ assert(elsIfs->topstat != NULL); assert(*(elsIfs->bottomElse) == NULL); /* elseif stats... should go to else part */ std::list* ep = new std::list(); ep->push_back(elsIfs->topstat); /* create real ifstat */ ret = new IfStat(condition, thenStats, ep, loc); /* attach else-part to bottom most else-list */ *(elsIfs->bottomElse) = elseStats; /* cleanup */ delete elsIfs; return *ret; } std::list& NodeFactory::makeSignalDecls( std::list& ids, enum ValDeclaration::Mode mode, bool isBus, Expression* varInit, SubtypeIndication* subtypeIndic, Location loc ) { std::list *v = new std::list(); for (std::list::iterator i = ids.begin(); i != ids.end(); i++) { SignalDeclaration *s = new SignalDeclaration(*i, mode, isBus, varInit, subtypeIndic, loc); v->push_back(s); assert(subtypeIndic); } util::MiscUtil::terminate(varInit); util::MiscUtil::terminate(subtypeIndic); return *v; } std::list& NodeFactory::makeConstantDecls( std::list& ids, Expression* varInit, SubtypeIndication* subtypeIndic, Location loc ) { std::list *v = new std::list(); for (std::list::iterator i = ids.begin(); i != ids.end(); i++) { ConstantDeclaration *s = new ConstantDeclaration(*i, varInit, subtypeIndic, true, loc); v->push_back(s); assert(subtypeIndic); } util::MiscUtil::terminate(varInit); util::MiscUtil::terminate(subtypeIndic); return *v; } std::list& NodeFactory::makeVarDecls( std::list& ids, Expression* varInit, SubtypeIndication* subtypeIndic, Location loc ) { std::list *v = new std::list(); for (std::list::iterator i = ids.begin(); i != ids.end(); i++) { VarDeclaration *s = new VarDeclaration( ValDeclaration::MODE_INOUT, *i, varInit, subtypeIndic, loc ); v->push_back(s); assert(subtypeIndic); } util::MiscUtil::terminate(varInit); util::MiscUtil::terminate(subtypeIndic); return *v; } std::list& NodeFactory::makeFuncInterfaceDecls( std::list& ids, Expression* varInit, enum ValDeclaration::Mode mode, enum ValDeclaration::ObjClass cls, SubtypeIndication* subtypeIndic, Location loc ) { std::list *v = new std::list(); if (mode != ValDeclaration::MODE_IN) { assert(! ids.empty()); // only in is allowed for functions. CompileError *ce = new CompileError(loc, "Wrong parameter mode for argument <" + *ids.front() + ">, setting to IN."); ErrorRegistry::addError(ce); } for (std::list::iterator i = ids.begin(); i != ids.end(); i++) { ValDeclaration *s = NULL; /* no class -> constant mode always in */ switch (cls) { case ValDeclaration::OBJ_CLASS_VARIABLE: { CompileError* ce = new CompileError(loc, "Object class VARIABLE not allowed " "for Function argument <" + **i + ">, using CONSTANT."); ErrorRegistry::addError(ce); /* fall through */ } case ValDeclaration::OBJ_CLASS_UNSPECIFIED: case ValDeclaration::OBJ_CLASS_CONSTANT: s = new ConstantDeclaration(*i, varInit, subtypeIndic, false, loc); break; case ValDeclaration::OBJ_CLASS_SIGNAL: s = new SignalDeclaration(*i, ValDeclaration::MODE_IN, false, varInit, subtypeIndic, loc ); break; } v->push_back(s); assert(subtypeIndic); } util::MiscUtil::terminate(varInit); util::MiscUtil::terminate(subtypeIndic); return *v; } std::list& NodeFactory::makeProcInterfaceDecls( std::list& ids, Expression* varInit, enum ValDeclaration::Mode mode, enum ValDeclaration::ObjClass cls, SubtypeIndication* subtypeIndic, Location loc ) { std::list *v = new std::list(); for (std::list::iterator i = ids.begin(); i != ids.end(); i++) { ValDeclaration *s = NULL; /* no class -> in -> constant others -> variable NOTE: it's unclear what the default mode of an interface element of a procedure is, in case no class is given. FAUhdlc will choose MODE_IN here. cf. IEEE Standard VHDL Language Reference Manual (ISBN 1-55397-376-8), p. 20 */ switch (cls) { case ValDeclaration::OBJ_CLASS_UNSPECIFIED: if (mode == ValDeclaration::MODE_IN) { s = new ConstantDeclaration(*i, varInit, subtypeIndic, false, loc); /* TODO issue warning if mode != MODE_IN */ } else { s = new VarDeclaration(mode, *i, varInit, subtypeIndic, loc); } break; case ValDeclaration::OBJ_CLASS_VARIABLE: s = new VarDeclaration(mode, *i, varInit, subtypeIndic, loc); break; case ValDeclaration::OBJ_CLASS_SIGNAL: s = new SignalDeclaration(*i, mode, false, varInit, subtypeIndic, loc); break; case ValDeclaration::OBJ_CLASS_CONSTANT: s = new ConstantDeclaration(*i, varInit, subtypeIndic, false, loc); switch (mode) { case ValDeclaration::MODE_IN: break; default: { CompileError *ce = new CompileError(loc, "Object class constant for <" + **i + "> must " "be of mode IN."); ErrorRegistry::addError(ce); } } break; } assert(subtypeIndic); v->push_back(s); } util::MiscUtil::terminate(varInit); util::MiscUtil::terminate(subtypeIndic); return *v; } struct NodeFactory::ContextItemS& NodeFactory::mergeContextItems( struct NodeFactory::ContextItemS& first, struct NodeFactory::ContextItemS& second ) { if (first.libClauses && second.libClauses) { listCombine(first.libClauses, second.libClauses); delete second.libClauses; } if (first.libClauses == NULL) { first.libClauses = second.libClauses; } if (first.useClauses && second.useClauses) { listCombine(first.useClauses, second.useClauses); delete second.useClauses; } if (first.useClauses == NULL) { first.useClauses = second.useClauses; } delete &second; return first; } CondalSigAssign& NodeFactory::makeCondalSigAssign(Name& trg, SeqStat& conds, Location loc) { CondalSigAssign& ret = *(new CondalSigAssign(&trg, &conds, loc)); NodeFactory::CondalSigAssignSetter setter = NodeFactory::CondalSigAssignSetter(trg); ret.accept(setter); return ret; } void NodeFactory::CondalSigAssignSetter::visit(SigAssignStat &node) { assert(node.target == NULL); // parser is wrong otherwise. node.target = &(this->target); /* _don't_ traverse here. (as it's not of our concern below.) */ } std::list& NodeFactory::makeRecordTypeElements( std::list &idlist, SubtypeIndication &subtype, Location loc ) { std::list *result = new std::list(); for (std::list::iterator i = idlist.begin(); i != idlist.end(); i++) { result->push_back( new RecordTypeElement(*i, &subtype, loc)); } SubtypeIndication* si = &subtype; util::MiscUtil::terminate(si); return *result; } Aggregate* NodeFactory::makeAggregateFromString( const std::string &stringLit, Location loc, const NameLookup &nl ) { std::list *elements = new std::list(); for (std::string::const_iterator i = stringLit.begin(); i != stringLit.end(); i++) { std::string *s = new std::string("'"); s->append(std::string(1, *i)); s->append("'"); std::list cands = nl.lookup(*s); if (cands.empty()) { UndefinedSymbol *us = new UndefinedSymbol(*s, loc); ErrorRegistry::addError(us); } FunctionCall *fc = new FunctionCall( new SimpleName( s, cands, loc), new std::list(), loc); ElementAssociation* assoc = new ElementAssociation(NULL, fc, loc); elements->push_back(assoc); } return new Aggregate(elements, loc); } void NodeFactory::registerEnumElems( const EnumerationType *e, SymbolTable &symbolTable, Symbol *typeSym ) { assert(e); assert(e->elements); unsigned int cnt = 0; for (std::list::const_iterator i = e->elements->begin(); i != e->elements->end(); i++) { //register the corresponding function for enumeration //elements. SimpleName *sn = new SimpleName(new std::string(*e->name), e->location); sn->candidates.push_back(typeSym); SubtypeIndication *si = new SubtypeIndication(sn, (*i)->location); (*i)->returnType = si; (*i)->isBuiltin = true; (*i)->builtin = new ReturnValue(cnt, e); symbolTable.registerSymbol(SYMBOL_FUNCTION, **i); cnt++; } } NodeFactory::TypeDeclHelper::TypeDeclHelper( std::list *indexConstraint, SubtypeIndication *elementType, Location loc, SymbolTable &s ) : enumType(NULL), typeDecl(NULL), conArrayBase(NULL), wasRecordType(false) { std::list *l = new std::list(); for (std::list::const_iterator i = indexConstraint->begin(); i != indexConstraint->end(); i++) { // FIXME this is not 100% correct: // in case the result is a universal type, it should get // converted to integer. // For now, just assume that it's a universal type, // and require integer as a result. // // One problem is, that the type resolution is non-const in // itself. Maybe it should be rewritten in a const part, // and in a non-const part. ResolveTypes r = ResolveTypes(s); TypeDeclaration *stdInt = s.getStdStandardType("integer"); assert(stdInt != NULL); r.typeCandidates.insert(stdInt); (*i)->accept(r); if ((*i)->type == NULL) { // type error occured, bail out early util::MiscUtil::lterminate(l); return; } l->push_back((*i)->type); } // create base type: anonymous unconstrained array. std::string n = s.getMangledPathName() + "__constraint_base__"; this->conArrayBase = new UnconstrainedArrayType( new std::string(n), l, elementType, loc); SubtypeIndication *t = new SubtypeIndication(this->conArrayBase, loc); t->indexConstraint = indexConstraint; this->typeDecl = t; } void NodeFactory::TypeDeclHelper::registerType( SymbolTable &symTab, NodeFactory::Identifier *id ) const { assert(id); assert(id->identifier); if (this->enumType) { assert(this->typeDecl == NULL); this->enumType->name = id->identifier; Symbol *sym = symTab.registerSymbol(SYMBOL_TYPE, *this->enumType); NodeFactory::registerEnumElems(this->enumType, symTab, sym); delete id; return; } // no enumeration type assert(this->enumType == NULL); if (this->typeDecl == NULL) { // type error must have been registered assert(false); // FIXME for debugging. return; } this->typeDecl->name = id->identifier; delete id; if (this->wasRecordType) { symTab.lateRegisterAttach(SYMBOL_TYPE, *this->typeDecl); // leave scope of record type symTab.popRegion(); return; } // base type for constrained array present? if (this->conArrayBase != NULL) { symTab.registerSymbol(SYMBOL_TYPE, *this->conArrayBase); } // fall through: neither a record type, nor an enumeration type symTab.registerSymbol(SYMBOL_TYPE, *this->typeDecl); } std::list* NodeFactory::TypeDeclHelper::flatten(void) const { std::list *ret = new std::list(); if (this->enumType) { ret->push_back(this->enumType); return ret; } if (this->conArrayBase != NULL) { ret->push_back(this->conArrayBase); } if (this->typeDecl == NULL) { // type error must have been registered. return ret; } ret->push_back(this->typeDecl); return ret; } AttributeSpecification * NodeFactory::handleAttributeSpecs( SimpleName *designator, std::list entityList, enum entityClassE classFilter, Expression *init, const SymbolTable &symTab ) { // find out attribute by designator. for (std::list::iterator i = designator->candidates.begin(); i != designator->candidates.end(); /* nothing */) { switch ((*i)->type) { case SYMBOL_ATTRIBUTE: i++; break; default: i = designator->candidates.erase(i); } } if (designator->candidates.size() != 1) { std::string s = "<" + *designator->name + "> does not refer" " to an Attribute."; CompileError *ce = new CompileError(*designator, s); ErrorRegistry::addError(ce); return NULL; } AttributeDeclaration *decl = dynamic_cast( &designator->candidates.front()->declaration); assert(decl != NULL); AttributeSpecification *spec = new AttributeSpecification(init, decl, designator->location); // attribute every referred to symbol that matches classFilter for (std::list::const_iterator i = entityList.begin(); i != entityList.end(); i++) { assert((*i)->candidates.empty()); assert((*i)->name != NULL); std::list syms = symTab.lookup(*(*i)->name); if (syms.empty()) { UndefinedSymbol *us = new UndefinedSymbol(*(*i)->name, (*i)->location); ErrorRegistry::addError(us); continue; } for (std::list::const_iterator j = syms.begin(); j != syms.end(); j++) { if (NodeFactory::isOfEntityClass(**j, classFilter)) { AttributableDeclaration *ad = dynamic_cast( &(*j)->declaration); assert(ad != NULL); // FIXME check if attribute already present // and report error if so. ad->attributes[*decl->name] = spec; } else { // FIXME if no "others"/"all" is present, // report an error (LRM 5.1) } } } return spec; } bool NodeFactory::isOfEntityClass(const Symbol &sym, enum entityClassE ec) { switch (ec) { case EC_ENTITY: switch (sym.type) { case SYMBOL_ENTITY: return true; default: return false; } /* not reached */ case EC_ARCHITECTURE: switch (sym.type) { case SYMBOL_ARCHITECTURE: return true; default: return false; } /* not reached */ case EC_CONFIGURATION: assert(false); /* not reached */ case EC_PROCEDURE: switch (sym.type) { case SYMBOL_PROCEDURE: return true; default: return false; } /* not reached */ case EC_FUNCTION: switch (sym.type) { case SYMBOL_FUNCTION: return true; default: return false; } /* not reached */ case EC_PACKAGE: switch (sym.type) { case SYMBOL_PACKAGE: return true; default: return false; } /* not reached */ case EC_TYPE: switch (sym.type) { case SYMBOL_TYPE: { /* must not be a subtype */ SubtypeIndication *si = dynamic_cast( &sym.declaration); return si == NULL; } default: return false; } /* not reached */ case EC_SUBTYPE: switch (sym.type) { case SYMBOL_TYPE: { /* must be a subtype */ SubtypeIndication *si = dynamic_cast( &sym.declaration); return si != NULL; } default: return false; } /* not reached */ case EC_CONSTANT: switch (sym.type) { case SYMBOL_PARAMETER: case SYMBOL_VARIABLE: { ValDeclaration *vd = dynamic_cast( &sym.declaration); assert(vd != NULL); switch (vd->storageClass) { case ValDeclaration::OBJ_CLASS_CONSTANT: return true; default: return false; } /* not reached */ } default: return false; } /* not reached */ case EC_SIGNAL: switch (sym.type) { case SYMBOL_PORT: case SYMBOL_PARAMETER: case SYMBOL_SIGNAL: { ValDeclaration *vd = dynamic_cast( &sym.declaration); assert(vd != NULL); switch (vd->storageClass) { case ValDeclaration::OBJ_CLASS_SIGNAL: return true; default: return false; } /* not reached */ } default: return false; } /* not reached */ case EC_VARIABLE: switch (sym.type) { case SYMBOL_PARAMETER: case SYMBOL_VARIABLE: { ValDeclaration *vd = dynamic_cast( &sym.declaration); assert(vd != NULL); switch (vd->storageClass) { case ValDeclaration::OBJ_CLASS_VARIABLE: return true; default: return false; } /* not reached */ } default: return false; } /* not reached */ case EC_COMPONENT: case EC_LABEL: case EC_LITERAL: case EC_UNITS: case EC_GROUP: case EC_FILE: assert(false); /* not reached */ } /* not reached */ return false; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/UnconstrainedArrayType.hpp0000664000175000017500000000425411305513466022607 0ustar potyrapotyra/* $Id: UnconstrainedArrayType.hpp 4850 2009-12-02 16:35:02Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __UNCONSTRAINED_ARRAY_TYPE_HPP_INCLUDED #define __UNCONSTRAINED_ARRAY_TYPE_HPP_INCLUDED #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/ast/SubtypeIndication.hpp" namespace ast { //! a VHDL array type. /** This class represents a VHDL unconstrained array type declaration. */ class UnconstrainedArrayType : public TypeDeclaration { public: //! c'tor /** @param declName name of the declaration. * @param indexTs list of index type marks. * @param elementT type mark of array elements. * @param loc location of the declaration. */ UnconstrainedArrayType( std::string *declName, std::list *indexTs, TypeDeclaration *elementT, Location loc ) : TypeDeclaration(declName, loc, BASE_TYPE_ARRAY), indexTypes(indexTs), elementType(elementT), numIndices(indexTs->size()) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name != NULL); stream << *this->name << ": ARRAY<>("; util::MiscUtil::listPut(this->indexTypes, stream, ", "); stream << ") OF " << this->elementType; } /** one type mark for each index. */ std::list *indexTypes; /** type mark of array elements */ TypeDeclaration *elementType; /** number of indices */ size_t numIndices; protected: /** Destructor */ virtual ~UnconstrainedArrayType() { util::MiscUtil::lterminate(indexTypes); } }; }; /* namespace ast */ #endif /* __UNCONSTRAINED_ARRAY_TYPE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AttributableDeclaration.cpp0000664000175000017500000000145611137610234022710 0ustar potyrapotyra/* $Id: AttributableDeclaration.hpp 3886 2008-11-18 15:54:19Z potyra $ * * AttributableDeclaration: base class for symbol declarations, that can have * attributes. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/AttributableDeclaration.hpp" namespace ast { AttributeSpecification * AttributableDeclaration::hasAttr(std::string attrName) const { std::map::const_iterator i = this->attributes.find(attrName); if (i == attributes.end()) { return NULL; } return i->second; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/SignalDeclaration.hpp0000664000175000017500000000411611137610234021504 0ustar potyrapotyra/* $Id: SignalDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SIGNAL_DECLARATION_HPP_INCLUDED #define __SIGNAL_DECLARATION_HPP_INCLUDED #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/Expression.hpp" namespace ast { //! Represents one Signal declaration. /** This class represents one VHDL signal declaration. */ class SignalDeclaration : public ValDeclaration { public: //! c'tor /** construct a Signal object. * @param declName name of the declared Signal. * @param pMode mode of the Signal (in, out, inout). * @param isBus declared with bus keyword (guarded signal)? * @param varInit initializer Expression for the constant. * @param subtype subtype indication * @param loc location of the SignalDeclaration. */ SignalDeclaration( std::string *declName, enum ValDeclaration::Mode pMode, bool isBus, Expression *varInit, SubtypeIndication *subtype, Location loc ) : ValDeclaration(pMode, declName, varInit, subtype, ValDeclaration::OBJ_CLASS_SIGNAL, loc), isGuarded(isBus) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "SIGNAL " << *this->name << " : " << this->subtypeIndic; if (this->init) { stream << " := " << this->init; } stream << ';'; } /** Is it a guarded signal? * currently this gets utterly ignored. */ bool isGuarded; }; }; /* namespace ast */ #endif /* __SIGNAL_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AttributeName.hpp0000664000175000017500000000266611137610234020675 0ustar potyrapotyra/* $Id: AttributeName.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ATTRIBUTE_NAME_HPP_INCLUDED #define __ATTRIBUTE_NAME_HPP_INCLUDED #include "frontend/ast/PrefixedName.hpp" namespace ast { //! a VHDL attribute name class AttributeName : public PrefixedName { public: //! c'tor /** @param n identifier of the name * @param pre prefix of the name * @param cands candidate symbols * @param loc corresponding location */ AttributeName( std::string *n, Expression *pre, std::list cands, Location loc ) : PrefixedName(n, pre, cands, loc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->prefix << '\'' << *this->name; } protected: //! d'tor virtual ~AttributeName() {} }; }; /* namespace ast */ #endif /* __ATTRIBUTE_NAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Process.hpp0000664000175000017500000000423411137610234017540 0ustar potyrapotyra/* $Id: Process.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PROCESS_HPP_INCLUDED #define __PROCESS_HPP_INCLUDED #include #include "frontend/ast/ConcurrentStat.hpp" #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/Name.hpp" #include "frontend/misc/Driver.hpp" namespace ast { //! a VHDL process. /** This class defines one VHDL process. */ class Process : public ConcurrentStat { public: //! c'tor /** @param sensitivities list of sensitivities. * @param decls list of declarations. * @param seqStatL list of sequential Statements. * @param loc location of process declaration. */ Process( std::list *sensitivities, std::list *decls, std::list *seqStatL, Location loc ) : ConcurrentStat(loc), sensitivityList(sensitivities), declarations(decls), seqStats(seqStatL) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "PROCESS"; if (this->name != NULL) { stream << " \"" << *this->name << '"'; } } /** sensitivity list */ std::list *sensitivityList; /** local declarations */ std::list *declarations; /** sequential statements */ std::list *seqStats; /** list of drivers */ std::list drivers; protected: /** Destructor */ virtual ~Process() { util::MiscUtil::lterminate(sensitivityList); util::MiscUtil::lterminate(declarations); util::MiscUtil::lterminate(seqStats); } }; }; /* namespace ast */ #endif /* __PROCESS_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AttributeDeclaration.cpp0000664000175000017500000000136211137610234022225 0ustar potyrapotyra/* $Id: AttributeDeclaration.cpp 4323 2009-01-27 13:48:12Z potyra $ * * AtributeDeclaration: AST Class representing an attribute declaration. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/AttributeDeclaration.hpp" #include "frontend/ast/TypeDeclaration.hpp" namespace ast { void AttributeDeclaration::put(std::ostream &stream) const { assert(this->name != NULL); assert(this->type != NULL); stream << "ATTRIBUTE " << *this->name << ':' << *this->type; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/Callable.hpp0000664000175000017500000000416611137610234017625 0ustar potyrapotyra/* $Id: Callable.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CALLABLE_HPP_INCLUDED #define __CALLABLE_HPP_INCLUDED #include "frontend/ast/AttributableDeclaration.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/SubprogBody.hpp" #include "frontend/misc/Driver.hpp" namespace ast { /** Abstract declaration of anything that can be called. * Basically a function or a procedure. */ class Callable : public AttributableDeclaration { public: //! c'tor /** @param declName declared name of the function or procedure. * @param args interface of the function or procedure. * @param knd kind of callable * @param loc location of the Callable. */ Callable( std::string* declName, std::list *args, enum SubprogBody::ProgKind knd, Location loc ) : AttributableDeclaration(declName, loc), arguments(args), kind(knd), definition(NULL), seen(false), containsWait(false) { if (this->arguments == NULL) { this->arguments = new std::list(); } } /** interface of the function or procedure, i.e. list of arguments */ std::list *arguments; /** kind of subprogram (func/proc) */ enum SubprogBody::ProgKind kind; /** corresponding SubprogBody, in case this Callable has also got an * implementation. */ SubprogBody *definition; /** only for parser: if true, this declaration is already part of the * SyntaxTree and should not get registered. */ bool seen; /** list of drivers */ std::list drivers; /** does the Callable contain a wait statement? * (set by WaitConditions visitor) */ bool containsWait; protected: /** Destructor */ virtual ~Callable() { util::MiscUtil::lterminate(arguments); util::MiscUtil::terminate(definition); } }; }; /* namespace ast */ #endif /* __CALLABLE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Package.hpp0000664000175000017500000000344011137610234017453 0ustar potyrapotyra/* $Id: Package.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PACKAGE_HPP_INCLUDED #define __PACKAGE_HPP_INCLUDED #include "frontend/ast/LibUnit.hpp" #include "frontend/ast/PackageBody.hpp" namespace ast { //! VHDL package declaration. /** This class represents a VHDL package declaration. */ class Package : public LibUnit { public: //! c'tor /** * @param declName name of the declared symbol. * @param libs library clauses * @param useCs use clauses * @param decls local declarations. * @param loc location of the declaration. */ Package( std::string* declName, std::list *libs, std::list* useCs, std::list* decls, Location loc ) : LibUnit(declName, libs, useCs, decls, loc), body(NULL) {} //! Accept a Visitor. // /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "PACKAGE " << *this->name << ';'; } /** referring PackageBody, mainly usefule for SymbolTable */ PackageBody* body; protected: /** Destructor */ virtual ~Package() { util::MiscUtil::terminate(body); } }; }; /* namespace ast */ #endif /* __PACKAGE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AttributeSpecification.cpp0000664000175000017500000000132611137610234022560 0ustar potyrapotyra/* $Id: AttributeSpecification.cpp 4323 2009-01-27 13:48:12Z potyra $ * AttributeSpecification: contains the combination of AttributeSpecification * to it's initializer Expression (AST node). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/AttributeSpecification.hpp" namespace ast { void AttributeSpecification::put(std::ostream &stream) const { stream << "ATTRIBUTE SPEC of " << *this->declaration << " IS " << *this->init; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/ValDeclaration.cpp0000664000175000017500000000154511163137341021011 0ustar potyrapotyra/* $Id: ValDeclaration.cpp 4421 2009-03-27 11:56:17Z potyra $ * * ValDeclaration: abstract representation of a signal, variable or constant * declaration. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/ValDeclaration.hpp" #include #include "frontend/visitor/ResolveTypes.hpp" namespace ast { bool ValDeclaration::isUnconstraint(void) const { assert(this->subtypeIndic != NULL); switch (this->subtypeIndic->baseType) { case BASE_TYPE_ARRAY: break; default: return false; } return ! ResolveTypes::isConstraintArray(this->subtypeIndic); } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/ExitStat.hpp0000664000175000017500000000362611137610234017673 0ustar potyrapotyra/* $Id: ExitStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __EXIT_STAT_HPP_INCLUDED #define __EXIT_STAT_HPP_INCLUDED #include "frontend/ast/ConditionedStat.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/LoopStat.hpp" namespace ast { //! a VHDL exit statement. /** This class represent a VHDL exit statement. */ class ExitStat : public ConditionedStat { public: //! c'tor /** @param optLoopLbl optional label referring to the enclosing loop * @param optCond optional condition. * @param loc location of the ExitStat. */ ExitStat( SimpleName *optLoopLbl, Expression *optCond, Location loc ) : ConditionedStat(optCond, loc), loopLabel(optLoopLbl), referredLoop(NULL) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "EXIT"; if (this->loopLabel) { stream << ' ' << this->loopLabel; } if (this->condition) { stream << " if " << this->condition; } } /** label referring to the loop */ SimpleName *loopLabel; /** loop statement being referred to */ LoopStat *referredLoop; protected: /** Destructor */ virtual ~ExitStat() { util::MiscUtil::terminate(loopLabel); //FIXME cycle! util::MiscUtil::terminate(referredLoop); } }; }; /* namespace ast */ #endif /* __EXIT_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Expression.hpp0000664000175000017500000000242111137610234020255 0ustar potyrapotyra/* $Id: Expression.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __EXPRESSION_HPP_INCLUDED #define __EXPRESSION_HPP_INCLUDED #include "frontend/ast/AstNode.hpp" #include "frontend/ast/Types.hpp" namespace ast { //! Generic class for an expression. /** This class is a generic class for any VHDL expressions. */ class Expression : public AstNode { public: //! c'tor /** @param loc location of the Expression. */ Expression(Location loc) : AstNode(loc), baseType(BASE_TYPE_UNSET), type(NULL) {} //! alternate c'tor /** @param loc Location of the expression. * @param baseT baseType of the expression. */ Expression( enum BaseType baseT, Location loc ) : AstNode(loc), baseType(baseT), type(NULL) {} /** base type of the expresion. */ enum BaseType baseType; /** type of the expression, will get set by ResolveTypes. */ TypeDeclaration *type; protected: /** Destructor */ virtual ~Expression(); }; }; /* namespace ast */ #endif /* __EXPRESSION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Library.hpp0000664000175000017500000000261411137610234017526 0ustar potyrapotyra/* $Id: Library.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LIBRARY_HPP_INCLUDED #define __LIBRARY_HPP_INCLUDED #include #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/LibUnit.hpp" namespace ast { //! a VHDL Design Library /** This class represents a VHDL design library. */ class Library : public SymbolDeclaration { public: //! c'tor /** @param libName name of the library */ Library( std::string *libName ) : SymbolDeclaration(libName, Location("library")) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name != NULL); stream << "LIBRARY " << this->name; } /** list of LibUnit */ std::list units; }; }; /* namespace ast */ #endif /* __LIBRARY_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ConcurrentStat.hpp0000664000175000017500000000145511137610234021102 0ustar potyrapotyra/* $Id: ConcurrentStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONCURRENT_STAT_HPP_INCLUDED #define __CONCURRENT_STAT_HPP_INCLUDED #include "frontend/ast/SymbolDeclaration.hpp" namespace ast { /** abstract base class for all concurrent statements */ class ConcurrentStat : public SymbolDeclaration { public: //! c'tor /** @param loc location of the concurrent statement */ ConcurrentStat( Location loc ) : SymbolDeclaration(NULL, loc) {} }; }; #endif /* __CONCURRENT_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/CompInstStat.hpp0000664000175000017500000000500211137610234020504 0ustar potyrapotyra/* $Id: CompInstStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __COMP_INST_STAT_HPP_INCLUDED #define __COMP_INST_STAT_HPP_INCLUDED #include "frontend/ast/Name.hpp" #include "frontend/ast/ConcurrentStat.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/Entity.hpp" namespace ast { /** a VHDL component instantiation */ class CompInstStat : public ConcurrentStat { public: //! c'tor /** @param entityN name of the entity. * @param genericM generic map * @param portM port map * @param loc location of the concurrent statement */ CompInstStat( Name *entityN, std::list *genericM, std::list *portM, Location loc ) : ConcurrentStat(loc), entityName(entityN), genericMap(genericM), portMap(portM) { assert(entityN != NULL); if (entityN->candidates.size() == 1) { Symbol *sym = entityN->candidates.front(); this->entity = dynamic_cast(&sym->declaration); } else { this->entity = NULL; } } //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { if (this->name != NULL) { stream << *this->name; } else { stream << "(null)"; } stream << " : " << this->entityName << " generic map ("; util::MiscUtil::listPut(this->genericMap, stream, ", "); stream << ") port map ("; util::MiscUtil::listPut(this->portMap, stream, ", "); stream << ");"; } /** name referring to the entity */ Name *entityName; /** generic map */ std::list *genericMap; /** port map */ std::list *portMap; /** referred to entity */ const Entity *entity; protected: /** Destructor */ virtual ~CompInstStat() { util::MiscUtil::terminate(entityName); util::MiscUtil::lterminate(genericMap); util::MiscUtil::lterminate(portMap); } }; }; /* namespace ast */ #endif /* __COMP_INST_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SymbolDeclaration.hpp0000664000175000017500000000313311502707332021534 0ustar potyrapotyra/* $Id: SymbolDeclaration.hpp 5084 2010-12-17 16:24:58Z potyra $ * * SymbolDeclaration: Base class for anything that declares a symbol. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SYMBOL_DECLARATION_HPP_INCLUDED #define __SYMBOL_DECLARATION_HPP_INCLUDED #include "frontend/ast/AstNode.hpp" #include namespace ast { /* forward declaration */ class DeclarativeRegion; //! Generic declaration of a symbol. /** This abstract class represents a generic declaration of a symbol, * e.g. the declaration of a signal, variable, function or type. */ class SymbolDeclaration : public AstNode { public: /** c'tor * @param declName name of the declared symbol. * @param loc Location of the symbol declaration. */ SymbolDeclaration( std::string *declName, Location loc ) : AstNode(loc), name(declName), region(NULL) {} //! return the intermediate code name of a symbol /** @return name to be used in the intermediate code. */ virtual std::string getICName(void) const; /** The name of the declared symbol */ std::string *name; /** declarative region created by the symbol, if any */ DeclarativeRegion *region; /** path name of the symbol */ std::string pathName; protected: /** Destructor */ virtual ~SymbolDeclaration() { delete this->name; } }; }; /* namespace ast */ #endif /* __SYMBOL_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AstNode.hpp0000664000175000017500000000413711502707332017463 0ustar potyrapotyra/* $Id: AstNode.hpp 5084 2010-12-17 16:24:58Z potyra $ * * Abstract base class for all nodes of the abstract syntax tree. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __AST_NODE_HPP_INCLUDED #define __AST_NODE_HPP_INCLUDED #include #include "frontend/visitor/Visitor.hpp" #include "frontend/ast/Location.hpp" #include "util/MiscUtil.hpp" #include "util/GarbageCollect.hpp" namespace ast { //! This is the abstract base class for all AST Nodes. /** All AST nodes need to derive from this class */ class AstNode : public util::GarbageCollect { public: //! c'tor /** @param loc source code location of the AST node. */ AstNode(Location loc) : location(loc), number(-1) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) = 0; /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const = 0; /** source location of the AST node. */ Location location; /** unique node number for Dot graphs */ int number; protected: /** d'tor, not used in this interface. */ virtual ~AstNode() {} }; /** operator to write node to a stream. * * @param stream stream to write the node to. * @param node node that should get written to stream. * @return modified stream. */ std::ostream& operator<<(std::ostream &stream, const AstNode &node); /** operator to write node to a stream. * * @param stream stream to write the node to. * @param node node that should get written to stream. If NULL, (null) gets * written. * @return modified stream. */ std::ostream& operator<<(std::ostream &stream, const AstNode *node); }; /* namespace ast */ #endif /* __AST_NODE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/RecordType.cpp0000664000175000017500000000163311137610234020175 0ustar potyrapotyra/* $Id: RecordType.cpp 4323 2009-01-27 13:48:12Z potyra $ * * RecordType: one VHDL Record type. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/RecordType.hpp" #include "frontend/ast/RecordTypeElement.hpp" namespace ast { RecordType::RecordType( std::string *id, std::list *elems, Location loc ) : TypeDeclaration(id, loc, BASE_TYPE_RECORD), elements(elems) { universal_integer cnt = 0; // set parent of elements, and element counter for (std::list::const_iterator i = elems->begin(); i != elems->end(); i++, cnt++) { (*i)->parent = this; (*i)->offset = cnt; } } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/AttributableDeclaration.hpp0000664000175000017500000000253611137610234022715 0ustar potyrapotyra/* $Id: AttributableDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * AttributableDeclaration: base class for symbol declarations, that can have * attributes. * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ATTRIBUTABLE_DECLARATION_HPP_INCLUDED #define __ATTRIBUTABLE_DECLARATION_HPP_INCLUDED #include #include "frontend/ast/AttributeSpecification.hpp" namespace ast { //! any symbol declaration that can have attributes. /** This class represents any Symbol declaration that can be attributed. */ class AttributableDeclaration : public SymbolDeclaration { public: AttributableDeclaration( std::string *declName, Location loc ) : SymbolDeclaration(declName, loc) {} /** is an attribute specifictaion with name present? * @param attrName name of the attribute to check for. * @return matching attribute specification, or NULL if not present. */ AttributeSpecification * hasAttr(std::string attrName) const; public: /** set of attributes */ std::map attributes; }; }; /* namespace ast */ #endif /* __ATTRIBUTABLE_DECLARATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/TemporaryName.hpp0000664000175000017500000000342711137610234020710 0ustar potyrapotyra/* $Id: TemporaryName.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TEMPORARY_NAME_HPP_INCLUDED #define __TEMPORARY_NAME_HPP_INCLUDED #include "frontend/ast/PrefixedName.hpp" namespace ast { //! An indexed name or slice name, resulting in a temporary. /** This class represents a VHDL indexed name or slice name. The index or * slice expression is stored as prefix, while the actual name is NULL, * because the VHDL grammar doesn't really represent a named object at this * point, but rather a temporary one. * In particular, a temporary name cannot be used for a procedure call or a * function call (as there would be no indication of what procedure or * function to call). */ class TemporaryName : public PrefixedName { public: //! c'tor /** @param pre prefix of the name * @param loc corresponding location */ TemporaryName( Expression *pre, Location loc ) : PrefixedName(NULL, pre, std::list(), loc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->prefix; } protected: //! d'tor virtual ~TemporaryName() {} }; }; /* namespace ast */ #endif /* __TEMPORARY_NAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AttributeSpecification.hpp0000664000175000017500000000352411137610234022567 0ustar potyrapotyra/* $Id: AttributeSpecification.hpp 4323 2009-01-27 13:48:12Z potyra $ * AttributeSpecification: contains the combination of AttributeSpecification * to it's initializer Expression (AST node). * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ATTRIBUTE_SPECIFICATION_HPP_INCLUDED #define __ATTRIBUTE_SPECIFICATION_HPP_INCLUDED #include "frontend/ast/Expression.hpp" #include "frontend/ast/AttributeDeclaration.hpp" namespace ast { class AttributeSpecification : public SymbolDeclaration { public: //! c'tor /** @param initializer initializer Expression * @param decl corresponding attribute declaration * @param loc Location of the specification */ AttributeSpecification( Expression *initializer, AttributeDeclaration *decl, Location loc ) : SymbolDeclaration(NULL, loc), init(initializer), declaration(decl) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const; /** initializer */ Expression *init; /** corresponding attribute declaration */ AttributeDeclaration *declaration; protected: /** destructor */ virtual ~AttributeSpecification() { util::MiscUtil::terminate(this->init); util::MiscUtil::terminate(this->declaration); } }; }; /* namespace ast */ #endif /* __ATTRIBUTE_SPECIFICATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/NodeFactory.tpp0000664000175000017500000000177211575354333020372 0ustar potyrapotyra/* $Id: NodeFactory.tpp 5095 2011-06-13 09:31:07Z potyra $ * vim:tabstop=8:shiftwidth=8:filetype=cpp:textwidth=72: * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include namespace ast { template std::list* NodeFactory::listCast(std::list* l) { U u = NULL; /* U should be a pointer */ T t __attribute__((__unused__)); t = u; /* won't work if classes aren't compatible */ assert(sizeof(std::list) == sizeof(std::list)); return reinterpret_cast< std::list* >(l); } template void NodeFactory::listCombine(std::list* dest, std::list* source) { assert(source); assert(dest); for (typename std::list::iterator i = source->begin(); i != source->end(); i++) { dest->push_back(*i); } } }; fauhdlc-20130704/frontend/ast/ElementAssociation.hpp0000664000175000017500000000413511502707332021712 0ustar potyrapotyra/* $Id: ElementAssociation.hpp 5084 2010-12-17 16:24:58Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ELEMENT_ASSOCIATION_HPP_INCLUDED #define __ELEMENT_ASSOCIATION_HPP_INCLUDED #include #include "frontend/ast/AstNode.hpp" #include "frontend/misc/RangeSet.hpp" namespace ast { //! one particular element association. /** This class represents VHDL element associations of an Aggregate. */ class ElementAssociation : public AstNode { public: //! c'tor /** @param formalChoices the formal (target) part containing a list * of Expressions. * @param actualExpression the actual (source) part containing the * actual value to be used. */ ElementAssociation( std::list *formalChoices, Expression *actualExpression, Location loc ) : AstNode(loc), choices(formalChoices), actual(actualExpression), range(NULL) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { util::MiscUtil::listPut(this->choices, stream, " | "); stream << " => " << this->actual; } /** formal part */ std::list *choices; /** actual part */ Expression *actual; /** RangeSet containing the locally static values of the choices. * May not be set in one corner case. */ RangeSet *range; protected: /** Destructor */ virtual ~ElementAssociation(void) { util::MiscUtil::lterminate(this->choices); util::MiscUtil::terminate(this->actual); delete this->range; } }; }; /* namespace ast */ #endif /* __ELEMENT_ASSOCIATION_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/FunctionCall.hpp0000664000175000017500000000676211137610234020513 0ustar potyrapotyra/* $Id: FunctionCall.hpp 4323 2009-01-27 13:48:12Z potyra $ * * AST node representing a function call. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __FUNCTION_CALL_HPP_INCLUDED #define __FUNCTION_CALL_HPP_INCLUDED #include #include #include "frontend/ast/Name.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/FunctionDeclaration.hpp" #include "frontend/ast/AssociationElement.hpp" namespace ast { //! represents a function call /** This class represents one VHDL Function call. */ class FunctionCall : public Expression { public: //! c'tor Functions with various arguments. /** @param fName name referring to the function declaration. * @param args argument list. * @param loc Location of the function call. */ FunctionCall( Name *fName, std::list *args, Location loc ) : Expression(loc), subprog(fName), arguments(args), definition(NULL) {} //! c'tor for unary Operator. /** @param fName name referring to the operator declaration. * @param operand operand of the unary operator. * @param loc Location of the operator symbol. */ FunctionCall( Name *fName, Expression *operand, Location loc ) : Expression(loc), subprog(fName), arguments(new std::list()), definition(NULL) { assert(operand); AssociationElement *elem = new AssociationElement(NULL, operand, operand->location); this->arguments->push_back(elem); } //! c'tor for binary Operator. /** @param fName name referring to the operator declaration. * @param left left operand of the binary operator. * @param right right operand of the binary operator. * @param loc Location of the operator symbol. */ FunctionCall( Name *fName, Expression *left, Expression *right, Location loc ) : Expression(loc), subprog(fName), arguments(new std::list()), definition(NULL) { assert(left); assert(right); AssociationElement *elem = new AssociationElement(NULL, left, left->location); this->arguments->push_back(elem); elem = new AssociationElement(NULL, right, right->location); this->arguments->push_back(elem); } //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->subprog; if ( (this->arguments != NULL) && (this->arguments->size() > 1)) { stream << "("; util::MiscUtil::listPut(this->arguments, stream, ", "); stream << ')'; } } /** name of the called function. */ Name *subprog; /** arguments of the function call. */ std::list *arguments; /** definition of the FunctionCall */ FunctionDeclaration *definition; protected: /** Destructor */ virtual ~FunctionCall() { util::MiscUtil::terminate(subprog); util::MiscUtil::lterminate(arguments); util::MiscUtil::terminate(definition); } }; }; /* namespace ast */ #endif /* __FUNCTION_CALL_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Expression.cpp0000664000175000017500000000104311137610234020247 0ustar potyrapotyra/* $Id: Expression.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/Expression.hpp" #include "frontend/ast/SubtypeIndication.hpp" namespace ast { Expression::~Expression() { util::MiscUtil::terminate(this->type); } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/ConstInteger.cpp0000664000175000017500000000377711137610234020534 0ustar potyrapotyra/* $Id: ConstInteger.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/SimpleName.hpp" #include "frontend/ast/PhysicalTypeUnit.hpp" #include "frontend/misc/Symbol.hpp" #include "frontend/reporting/SyntaxError.hpp" #include "util/MiscUtil.hpp" namespace ast { ConstInteger::ConstInteger( universal_integer val, Name* unit, Location loc ) : Expression(BASE_TYPE_INTEGER, loc), physUnit(unit), value(ConstInteger::makeValue(unit, val)) {} ConstInteger::ConstInteger( universal_real val, Name* unit, Location loc ) : Expression(BASE_TYPE_INTEGER, loc), physUnit(unit), value(ConstInteger::makeValue(unit, val)) {} template universal_integer ConstInteger::makeValue(Name *unit, T numericValue) { assert(unit != NULL); if (unit->candidates.size() != 1) { std::string msg = util::MiscUtil::toString(unit->location); msg += " Not a physical literal: <"; msg += util::MiscUtil::toString(unit); msg += ">"; throw yy::SyntaxError(msg); } Symbol *sym = unit->candidates.front(); // FIXME? must this really be a simple name (expanded names are // stored as SimpleName as well!). const SimpleName *sn = dynamic_cast(unit); if ((sym->type != SYMBOL_UNIT) || (sn == NULL)) { std::string msg = util::MiscUtil::toString(unit->location); msg += " Not a physical literal: <"; msg += util::MiscUtil::toString(unit); msg += ">"; throw yy::SyntaxError(msg); } const PhysicalTypeUnit *pu = dynamic_cast(&sym->declaration); assert(pu != NULL); return static_cast( static_cast(pu->factor) * static_cast(numericValue)); } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/Entity.hpp0000664000175000017500000000513511137610234017377 0ustar potyrapotyra/* $Id: Entity.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ENTITY_HPP_INCLUDED #define __ENTITY_HPP_INCLUDED #include #include #include #include "frontend/ast/AttributableDeclaration.hpp" #include "frontend/ast/LibUnit.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" namespace ast { //! One VHDL entity definition. /** This node represents one Entity definition in VHDL. */ class Entity : public LibUnit { public: //! c'tor /** initialize members * @param ename name of entity. * @param plist list of associated Ports. * @param glist list of associated Generics. * @param libs library clauses * @param useCs use clauses. * @param decls list of declared items. * @param loc location of the Architecture declaration. */ Entity( std::string* ename, std::list *plist, std::list *glist, std::list *libs, std::list *useCs, std::list *decls, Location loc ) : LibUnit(ename, libs, useCs, decls, loc), ports(plist), generics(glist) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "ENTITY " << *this->name; if ((this->generics == NULL) && (this->ports == NULL)) { return; } stream << " IS"; if (this->generics != NULL) { stream << " GENERIC ("; util::MiscUtil::listPut(this->generics, stream, ", "); stream << ");"; } if (this->ports != NULL) { stream << " PORT ("; util::MiscUtil::listPut(this->ports, stream, ", "); stream << ");"; } } /** List of associated Ports. */ std::list *ports; /** List of associated Generics */ std::list *generics; protected: /** Destructor */ virtual ~Entity() { util::MiscUtil::lterminate(ports); util::MiscUtil::lterminate(generics); } }; }; /* namespace ast */ #endif /* __ENTITY_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/PackageBody.hpp0000664000175000017500000000313511137610234020272 0ustar potyrapotyra/* $Id: PackageBody.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PACKAGE_BODY_HPP_INCLUDED #define __PACKAGE_BODY_HPP_INCLUDED #include "frontend/ast/LibUnit.hpp" namespace ast { //! VHDL package body declaration /** This class represents a VHDL package body declaration. */ class PackageBody : public LibUnit { public: //! c'tor /** * @param declName name of the declared symbol. * @param libs library clauses * @param useCs use clauses * @param decls local declarations. * @param loc location of the declaration. */ PackageBody( std::string* declName, std::list *libs, std::list *useCs, std::list *decls, Location loc ) : LibUnit(declName, libs, useCs, decls, loc) {} //! Accept a Visitor. // /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << "PACKAGE BODY " << *this->name; } }; }; /* namespace ast */ #endif /* __PACKAGE_BODY_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Name.cpp0000664000175000017500000000156411137610234017000 0ustar potyrapotyra/* $Id: Name.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/Name.hpp" #include "frontend/misc/Symbol.hpp" namespace ast { std::string Name::getName(void) const throw(std::logic_error) { if (this->candidates.size() != 1) { throw std::logic_error( "getName() called, but definition is unclear."); } Symbol *sym = this->candidates.front(); return sym->declaration.getICName(); } SymbolDeclaration* Name::getDeclaration(void) const { assert(this->candidates.size() == 1); Symbol *sym = this->candidates.front(); return &sym->declaration; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/SeqStat.hpp0000664000175000017500000000201211137610234017476 0ustar potyrapotyra/* $Id: SeqStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SEQ_STAT_HPP_INCLUDED #define __SEQ_STAT_HPP_INCLUDED #include #include "frontend/ast/SymbolDeclaration.hpp" namespace ast { //! generic sequential statement. /** generic base class for sequential statements. */ class SeqStat : public SymbolDeclaration { public: //! c'tor /** @param loc Location of the sequential statement. */ SeqStat(Location loc) : SymbolDeclaration(NULL, loc) {} //! c'tor /** * @param lbl label of the sequential statement. * @param loc Location of the sequential statement. */ SeqStat( std::string *lbl, Location loc ) : SymbolDeclaration(lbl, loc) {} }; }; /* namespace ast */ #endif /* __SEQ_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ConstInteger.hpp0000664000175000017500000000444011137610234020525 0ustar potyrapotyra/* $Id: ConstInteger.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONST_INTEGER_HPP_INCLUDED #define __CONST_INTEGER_HPP_INCLUDED #include "frontend/ast/Expression.hpp" #include "frontend/visitor/Visitor.hpp" #include "frontend/ast/Types.hpp" #include "frontend/ast/Name.hpp" namespace ast { //! One constant integer. /** This class represents once constant VHDL integer. */ class ConstInteger : public Expression { public: //! c'tor /** @param val value of the VHDL integer. * @param unit physical unit. * @param loc location of the definition. */ ConstInteger( universal_integer val, Name* unit, Location loc); //! c'tor /** @param val value of the VHDL integer. * @param unit physical unit. * @param loc location of the definition. */ ConstInteger( universal_real val, Name* unit, Location loc); //! c'tor (no physical unit given). /** @param val value of the VHDL integer. * @param loc location of the definition. */ ConstInteger( universal_integer val, Location loc ) : Expression(BASE_TYPE_INTEGER, loc), physUnit(NULL), value(val) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->value; } /** Name of the physical unit, if any. */ Name *physUnit; /** Value of the integer. */ universal_integer value; private: //! determine the value by given Unit Name. /** @param unit unit name. * @param numericValue real/integer factor. * @return integral value of the constant. */ template static universal_integer makeValue(Name *unit, T numericValue); }; }; /* namespace ast */ #endif /* __CONST_INTEGER_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SimpleName.hpp0000664000175000017500000000547011254460367020171 0ustar potyrapotyra/* $Id: SimpleName.hpp 4675 2009-09-17 16:16:55Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SIMPLE_NAME_HPP_INCLUDED #define __SIMPLE_NAME_HPP_INCLUDED #include "frontend/ast/Name.hpp" #include "frontend/misc/Driver.hpp" namespace ast { //! a VHDL simple name /** This class represents a VHDL simple name, either because it was parsed * from only one identifier, or because it was an expanded name which is * reduced to the meaning of a simple name. */ class SimpleName : public Name { public: //! c'tor /** @param n identifier of the name * @param cands list of candidate symbols. * @param loc corresponding location */ SimpleName( std::string *n, std::list cands, Location loc ) : Name(n, cands, loc), driver(NULL) {} //! c'tor /** @param n identifier of the name * @param loc corresponding location */ SimpleName( std::string *n, Location loc ) : Name(n, std::list(), loc), driver(NULL) {} //! c'tor /** @param n identifier of the name * @param loc corresponding location */ SimpleName( const char *n, Location loc ) : Name(new std::string(n), std::list(), loc), driver(NULL) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); std::list names = this->prefixStrings; names.push_back(this->name); util::MiscUtil::listPut(&names, stream, "."); } //! does the name refer to a signal? /** @return true, if the name refers to a Signal. */ bool isSignal(void) const; //! equality operator /** check if one SimpleName is semantically equal to another * SimpleName. * @param other other SimpleName to check for equality. * @return true, if both names have the same semantic meaning. */ bool operator==(const SimpleName &other) const; /** optional prefix for expanded names (only for error reporting * purposes) */ std::list prefixStrings; /** associated driver, if any */ const Driver *driver; protected: /** d'tor*/ virtual ~SimpleName() { for (std::list::iterator i = this->prefixStrings.begin(); i != this->prefixStrings.end(); i++) { delete *i; } } }; }; /* namespace ast */ #endif /* __SIMPLE_NAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/DiscreteRange.cpp0000664000175000017500000001053311244522562020640 0ustar potyrapotyra/* $Id: DiscreteRange.cpp 4579 2009-08-24 14:36:34Z potyra $ * * DiscreteRange: AST node for a discrete range. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/DiscreteRange.hpp" #include "frontend/ast/SubtypeIndication.hpp" #include "frontend/ast/ConstInteger.hpp" #include "frontend/ast/RangeConstraintType.hpp" #include "frontend/reporting/ErrorRegistry.hpp" #include namespace ast { DiscreteRange::DiscreteRange( SubtypeIndication *si, Location loc ) : Expression(loc), from(NULL), to(NULL), direction(DIRECTION_UP), rangeName(NULL) { try { this->setFromAndTo(si); } catch(std::runtime_error) { std::string msg = "Not a constraint type found for range " + util::MiscUtil::toString(si); CompileError *ce = new CompileError(*this, msg); ErrorRegistry::addError(ce); } } void DiscreteRange::put(std::ostream &stream) const { stream << "RANGE "; if (this->rangeName) { stream << this->rangeName << ';'; return; } stream << this->from; switch(this->direction) { case DIRECTION_DOWN: stream << " DOWNTO "; break; case DIRECTION_UP: stream << " TO "; break; } stream << this->to; } universal_integer DiscreteRange::getArraySize(void) const { assert(this->from != NULL); assert(this->to != NULL); ConstInteger *left = dynamic_cast(this->from); ConstInteger *right = dynamic_cast(this->to); assert(left != NULL); assert(right != NULL); //FIXME might do a second try with ConstantPropagation universal_integer sz = right->value - left->value + 1; switch(this->direction) { case DIRECTION_UP: break; case DIRECTION_DOWN: sz = left->value - right->value + 1; break; } if (sz < 0) { return 0; } return sz; } universal_integer DiscreteRange::getLowerBound(void) const { assert(this->from != NULL); assert(this->to != NULL); ConstInteger *left = dynamic_cast(this->from); ConstInteger *right = dynamic_cast(this->to); assert(left != NULL); assert(right != NULL); //FIXME might do a second try with ConstantPropagation switch(this->direction) { case DIRECTION_UP: return left->value; break; case DIRECTION_DOWN: return right->value; break; } // not reached. assert(false); return 0; } universal_integer DiscreteRange::getUpperBound(void) const { assert(this->from != NULL); assert(this->to != NULL); ConstInteger *left = dynamic_cast(this->from); ConstInteger *right = dynamic_cast(this->to); assert(left != NULL); assert(right != NULL); //FIXME might do a second try with ConstantPropagation switch(this->direction) { case DIRECTION_UP: return right->value; break; case DIRECTION_DOWN: return left->value; break; } // not reached. assert(false); return 0; } universal_integer DiscreteRange::getLeftBound(void) const { assert(this->from != NULL); ConstInteger *left = dynamic_cast(this->from); assert(left != NULL); return left->value; } universal_integer DiscreteRange::getRightBound(void) const { assert(this->to != NULL); ConstInteger *right = dynamic_cast(this->to); assert(right != NULL); return right->value; } void DiscreteRange::setFromAndTo(const SubtypeIndication *si) throw(std::runtime_error) { assert(si != NULL); if (si->constraint != NULL) { assert(si->constraint->from != NULL); assert(si->constraint->to != NULL); this->from = si->constraint->from; this->to = si->constraint->to; this->direction = si->constraint->direction; return; } /* not found */ const SubtypeIndication *parent = dynamic_cast(si->declaration); if (parent != NULL) { this->setFromAndTo(parent); return; } /* might be a RangeConstraintType */ const RangeConstraintType *r = dynamic_cast(si->declaration); if (r == NULL) { throw std::runtime_error("unconstraint"); } assert(r->constraint != NULL); assert(r->constraint->from != NULL); assert(r->constraint->to != NULL); this->from = r->constraint->from; this->to = r->constraint->to; this->direction = r->constraint->direction; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/LibUnit.hpp0000664000175000017500000000307511137610234017472 0ustar potyrapotyra/* $Id: LibUnit.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LIB_UNIT_HPP_INCLUDED #define __LIB_UNIT_HPP_INCLUDED #include #include #include "frontend/ast/AttributableDeclaration.hpp" #include "frontend/ast/SimpleName.hpp" namespace ast { //! VHDL library unit /** a VHDL library unit */ class LibUnit : public AttributableDeclaration { public: //! c'tor /** * @param declName name of the declared symbol. * @param libs library clauses * @param useCs use clauses * @param decls local declarations. * @param loc location of the declaration. */ LibUnit( std::string *declName, std::list *libs, std::list* useCs, std::list* decls, Location loc ) : AttributableDeclaration(declName, loc), libClauses(libs), useClauses(useCs), declarations(decls) {} /** library clauses */ std::list *libClauses; /** use clauses */ std::list *useClauses; /** declarations */ std::list *declarations; protected: /** Destructor */ virtual ~LibUnit() { util::MiscUtil::lterminate(libClauses); util::MiscUtil::lterminate(useClauses); util::MiscUtil::lterminate(declarations); } }; }; /* namespace ast */ #endif /* __LIB_UNIT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SelectedName.hpp0000664000175000017500000000265311137610234020456 0ustar potyrapotyra/* $Id: SelectedName.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SELECTED_NAME_HPP_INCLUDED #define __SELECTED_NAME_HPP_INCLUDED #include "frontend/ast/PrefixedName.hpp" namespace ast { class SelectedName : public PrefixedName { public: //! c'tor /** @param n identifier of the name * @param pre prefix of the name * @param cands candidate symbols * @param loc corresponding location */ SelectedName( std::string *n, Expression *pre, std::list cands, Location loc ) : PrefixedName(n, pre, cands, loc) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << this->prefix << '.' << *this->name; } protected: //! d'tor virtual ~SelectedName() {} }; }; /* namespace ast */ #endif /* __SELECTED_NAME_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SigAssignStat.hpp0000664000175000017500000000342211137610234020643 0ustar potyrapotyra/* $Id: SigAssignStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SIG_ASSIGN_STAT_HPP_INLCUDED #define __SIG_ASSIGN_STAT_HPP_INLCUDED #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/Name.hpp" #include "frontend/ast/WaveFormElem.hpp" namespace ast { /** Signal assign statement */ class SigAssignStat : public SeqStat { public: //! c'tor /** @param trg target of the SigAssignStat. * @param waveFrm WaveForm that should get assigned. * @param loc location of the SigAssignStat. */ SigAssignStat( Name *trg, std::list *waveFrm, Location loc ) : SeqStat(loc), target(trg), waveForm(waveFrm) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << this->target << " <= "; util::MiscUtil::listPut(this->waveForm, stream, ", "); stream << ';'; } /** target */ Expression *target; /** WaveForm that should get assigned to target */ std::list *waveForm; protected: /** Destructor */ virtual ~SigAssignStat() { util::MiscUtil::terminate(target); util::MiscUtil::lterminate(waveForm); } }; }; #endif /* __SIG_ASSIGN_STAT_HPP_INLCUDED */ fauhdlc-20130704/frontend/ast/ProcCallStat.hpp0000664000175000017500000000405411137610234020455 0ustar potyrapotyra/* $Id: ProcCallStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PROC_CALL_STAT_HPP_INCLUDED #define __PROC_CALL_STAT_HPP_INCLUDED #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/AssociationElement.hpp" #include "frontend/ast/Name.hpp" #include "frontend/ast/ProcedureDeclaration.hpp" namespace ast { /** a VHDL procedure call statement. */ class ProcCallStat : public SeqStat { public: //! c'tor /** @param pName name of the called procedure * @param args List of arguments (List of AssociationElement). * @param loc location of the procedure call. */ ProcCallStat( Name *pName, std::list *args, Location loc ) : SeqStat(loc), subprog(pName), definition(NULL), arguments(args) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << subprog << '('; if (this->arguments != NULL) { util::MiscUtil::listPut(this->arguments, stream, ", "); } else { stream << "open"; } stream << ");"; } /** name referring to the procedure */ Name *subprog; /** definition as resolved by ResolveTypes. */ ProcedureDeclaration *definition; /** arguments of the procedure call (optional) */ std::list *arguments; protected: /** Destructor */ virtual ~ProcCallStat() { util::MiscUtil::terminate(subprog); util::MiscUtil::lterminate(arguments); } }; }; /* namespace ast */ #endif /* __PROC_CALL_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Architecture.hpp0000664000175000017500000000533111137610234020543 0ustar potyrapotyra/* $Id: Architecture.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ARCHITECTURE_HPP_INCLUDED #define __ARCHITECTURE_HPP_INCLUDED #include #include "frontend/ast/LibUnit.hpp" #include "frontend/ast/ConcurrentStat.hpp" #include "frontend/ast/Location.hpp" #include "frontend/ast/Name.hpp" #include "frontend/ast/Entity.hpp" #include "frontend/ast/CompInstStat.hpp" namespace ast { /** One VHDL architecture */ class Architecture : public LibUnit { public: //! c'tor /** @param declName name of the architecture. * @param entName name of the referring Entity. * @param decls local declarations. * @param concStats concurrent statements. * @param libs library clauses * @param useCs use clauses * @param loc location of the Architecture declaration. */ Architecture( std::string *declName, Name *entName, std::list* decls, std::list* concStats, std::list *libs, std::list* useCs, Location loc ) : LibUnit(declName, libs, useCs, decls, loc), entityName(entName), concurrentStats(concStats) { assert(entName != NULL); assert(entName->candidates.size() < 2); if (entName->candidates.size() == 1) { Symbol *s = entName->candidates.front(); this->entity = dynamic_cast(&s->declaration); assert(this->entity != NULL); } // otherwise a name error was reported by the parser already. } //! Accept a Visitor. // /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name != NULL); stream << "Architecture " << *this->name << " of " << this->entityName; } /** The referring entity name */ Name *entityName; /** concurrent stats of Entity */ std::list *concurrentStats; /** the referring entity */ Entity *entity; protected: /** Destructor, decrease reference counts */ virtual ~Architecture() { util::MiscUtil::terminate(this->entityName); util::MiscUtil::terminate(this->entity); util::MiscUtil::lterminate(this->concurrentStats); } }; }; /* namespace ast */ #endif /* __ARCHITECTURE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Types.cpp0000664000175000017500000000341411137610234017220 0ustar potyrapotyra/* $Id: Types.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Types: base types of VHDL. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/Types.hpp" #include namespace ast { enum BaseType operator &&(enum BaseType left, enum BaseType right) { if (left == right) { return left; } switch(left) { case BASE_TYPE_INTEGER: switch (right) { case BASE_TYPE_REAL: return right; default: return BASE_TYPE_UNSET; } case BASE_TYPE_REAL: switch (right) { case BASE_TYPE_INTEGER: return left; default: return BASE_TYPE_UNSET; } case BASE_TYPE_RANGE_INT: switch (right) { case BASE_TYPE_RANGE_REAL: return right; default: return BASE_TYPE_UNSET; } case BASE_TYPE_RANGE_REAL: switch (right) { case BASE_TYPE_RANGE_INT: return left; default: return BASE_TYPE_UNSET; } case BASE_TYPE_ENUM: switch (right) { case BASE_TYPE_ENUM: return left; default: return BASE_TYPE_UNSET; }; default: break; } return BASE_TYPE_UNSET; } enum intermediate::OpType toOpType(enum BaseType src) { switch (src) { case BASE_TYPE_ARRAY: case BASE_TYPE_RECORD: return intermediate::OP_TYPE_POINTER; case BASE_TYPE_REAL: return intermediate::OP_TYPE_REAL; case BASE_TYPE_ENUM: case BASE_TYPE_INTEGER: return intermediate::OP_TYPE_INTEGER; case BASE_TYPE_UNSET: case BASE_TYPE_RANGE_REAL: case BASE_TYPE_RANGE_INT: /* must not happend */ assert(false); break; } /* not reached */ return intermediate::OP_TYPE_POINTER; } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/WhileLoopStat.hpp0000664000175000017500000000326711137610234020665 0ustar potyrapotyra/* $Id: WhileLoopStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __WHILE_LOOP_STAT_HPP_INCLUDED #define __WHILE_LOOP_STAT_HPP_INCLUDED #include "frontend/ast/LoopStat.hpp" #include "frontend/ast/Expression.hpp" namespace ast { //! VHDL while loop. /** a VHDL while loop statement. */ class WhileLoopStat : public LoopStat { public: //! c'tor /** @param lbl optional label of the loop. * @param stats sequential statements enclosed by the loop. * @param cond while-condition of the loop. * @param loc location of the while statement. */ WhileLoopStat( std::string *lbl, std::list *stats, Expression *cond, Location loc ) : LoopStat(lbl, stats, loc), condition(cond) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "WHILE " << this->condition; } /** while condition */ Expression *condition; protected: /** Destructor */ virtual ~WhileLoopStat() { util::MiscUtil::terminate(condition); } }; }; /* namespace ast */ #endif /* __WHILE_LOOP_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/AssertStat.hpp0000664000175000017500000000336311137610234020221 0ustar potyrapotyra/* $Id: AssertStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ASSERT_STAT_HPP_INCLUDED #define __ASSERT_STAT_HPP_INCLUDED #include "frontend/ast/ConditionedStat.hpp" namespace ast { /** a sequential ASSERT stat */ class AssertStat : public ConditionedStat { public: //! c'tor /** @param cond condition when the assert statement should be * evaluated. * @param optReport expression to report * @param optSeverity severity of report * @param loc location of the assert statement. */ AssertStat( Expression *cond, Expression *optReport, Expression *optSeverity, Location loc ) : ConditionedStat(cond, loc), report(optReport), severity(optSeverity) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "Assert"; } /** what to report (optional) */ Expression *report; /** severity expression (optional) */ Expression *severity; protected: /** destructor */ virtual ~AssertStat() { util::MiscUtil::terminate(this->report); util::MiscUtil::terminate(this->severity); } }; }; /* namespace ast */ #endif /* __ASSERT_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/RecordType.hpp0000664000175000017500000000324411137610234020202 0ustar potyrapotyra/* $Id: RecordType.hpp 4323 2009-01-27 13:48:12Z potyra $ * * RecordType: one VHDL Record type. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RECORD_TYPE_HPP_INCLUDED #define __RECORD_TYPE_HPP_INCLUDED #include #include "frontend/ast/TypeDeclaration.hpp" #include "frontend/ast/RecordTypeElement.hpp" namespace ast { //! VHDL record type. /** This class represents one VHDL record type declaration. */ class RecordType : public TypeDeclaration { public: //! c'tor /** @param id type name of declared type. * @param elems elements of record. * @param loc location of declaration. */ RecordType( std::string *id, std::list *elems, Location loc ); //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor &visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name != NULL); stream << "RECORD " << *this->name; } /** record elements */ std::list *elements; protected: /** Destructor */ virtual ~RecordType() { util::MiscUtil::lterminate(elements); } }; }; /* namespace ast */ #endif /* __RECORD_TYPE_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/SymbolDeclaration.cpp0000664000175000017500000000153411137610234021530 0ustar potyrapotyra/* $Id: SymbolDeclaration.cpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2008-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "frontend/ast/SymbolDeclaration.hpp" #include #include "util/mangle_names.h" namespace ast { std::string SymbolDeclaration::getICName(void) const { char buffer[2048]; assert(this->pathName.size() > 2); // strip leading and tailing ':' std::string m = this->pathName.substr(1, this->pathName.size() - 2); int ret = mangle_name(m.c_str(), buffer, sizeof(buffer)); assert(static_cast(ret) < sizeof(buffer)); return std::string(buffer); } }; /* namespace ast */ fauhdlc-20130704/frontend/ast/ValDeclaration.hpp0000664000175000017500000000557411137610234021022 0ustar potyrapotyra/* $Id: ValDeclaration.hpp 4323 2009-01-27 13:48:12Z potyra $ * * ValDeclaration: abstract representation of a signal, variable or constant * declaration. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __VAL_DECLARATION_HPP_INCLUDDED #define __VAL_DECLARATION_HPP_INCLUDDED #include #include "frontend/ast/AttributableDeclaration.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/SubtypeIndication.hpp" namespace ast { //! A signal, variable or constant declaration. /** This class represents a declaration of either a VHDL signal, * a VHDL variable or a VHDL constant. */ class ValDeclaration : public AttributableDeclaration { public: /** VHDL mode attribute (in, out, inout) */ enum Mode { MODE_IN, /**< access mode in */ MODE_OUT, /**< access mode out */ MODE_INOUT /**< access mode inout */ }; /** Storage class (signal, constant, variable) */ enum ObjClass { OBJ_CLASS_SIGNAL, /**< signal */ OBJ_CLASS_VARIABLE, /**< variable */ OBJ_CLASS_CONSTANT, /**< constant */ OBJ_CLASS_UNSPECIFIED /**< unspecified */ }; /** mode in which this declaration is used */ enum UsageMode { /** not used at all */ USAGE_NONE = 0, /** read from VHDL */ USAGE_READ = 1 << 0, /** written to from VHDL */ USAGE_WRITE = 1 << 1, /** signal used in a foreign component */ USAGE_FOREIGN = 1 << 2 }; /** c'tor * @param accessMode mode of the Signal (in, out, inout). * @param declName the declared name * @param varInit initializer Expression for the value. * @param subtype subtype indication of the value. * @param sc storage class for convenience. * @param loc Location of the declaration. */ ValDeclaration( enum Mode accessMode, std::string *declName, Expression *varInit, SubtypeIndication *subtype, enum ObjClass sc, Location loc ) : AttributableDeclaration(declName, loc), init(varInit), mode(accessMode), subtypeIndic(subtype), storageClass(sc), usage(USAGE_NONE) {} /** initial value (optional) */ Expression *init; /** access mode */ enum Mode mode; /** subtype indication */ SubtypeIndication *subtypeIndic; /** storage class for convenience */ enum ObjClass storageClass; /** does the declaration denote an Unconstraint array? * @return true if the declaration denotes an unconstraint array, * false otherwise. */ bool isUnconstraint(void) const; /** useage of the declaration */ int usage; protected: /** Destructor */ virtual ~ValDeclaration() { util::MiscUtil::terminate(init); util::MiscUtil::terminate(subtypeIndic); } }; }; /* namespace ast */ #endif /* __VAL_DECLARATION_HPP_INCLUDDED */ fauhdlc-20130704/frontend/ast/CaseStat.hpp0000664000175000017500000000325611137610234017634 0ustar potyrapotyra/* $Id: CaseStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CASE_STAT_HPP_INCLUDED #define __CASE_STAT_HPP_INCLUDED #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/Expression.hpp" #include "frontend/ast/CaseAlternative.hpp" namespace ast { /** a VHDL case statement. */ class CaseStat : public SeqStat { public: //! c'tor /** @param ref reference Expression. * @param choices List of CaseAlternative nodes. * @param loc Location of the CaseStat. */ CaseStat( Expression* ref, std::list* choices, Location loc ) : SeqStat(loc), select(ref), alternatives(choices) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { stream << "case"; } /** select value */ Expression* select; /** list of CaseAlternative nodes */ std::list* alternatives; protected: /** Destructor */ virtual ~CaseStat() { util::MiscUtil::terminate(select); util::MiscUtil::lterminate(alternatives); } }; }; /* namespace ast */ #endif /* __CASE_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/ConditionedStat.hpp0000664000175000017500000000260111137610234021211 0ustar potyrapotyra/* $Id: ConditionedStat.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONDITIONED_STAT_HPP_INCLUDED #define __CONDITIONED_STAT_HPP_INCLUDED #include "frontend/ast/SeqStat.hpp" #include "frontend/ast/Expression.hpp" namespace ast { //! Sequential statement with a condition. /** This class defines a sequential statement, that will get evaluated only, * if the condition evaluates to true, or is NULL. * Abstract class. */ class ConditionedStat : public SeqStat { public: //! c'tor /** @param cond condition (may be NULL), has a boolean result. * @param loc location of the ConditionedStat. */ ConditionedStat( Expression *cond, Location loc ) : SeqStat(loc), condition(cond) {} /** condition, that may either be NULL, or needs to evaluate to * a boolean value. If it's present, the SeqStat will only get * evaluated, if the condition is true. */ Expression *condition; protected: /** Destructor */ virtual ~ConditionedStat() { util::MiscUtil::terminate(condition); } }; }; /* namespace ast */ #endif /* __CONDITIONED_STAT_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/Types.hpp0000664000175000017500000000264411137610234017231 0ustar potyrapotyra/* $Id: Types.hpp 4323 2009-01-27 13:48:12Z potyra $ * * Types: base types of VHDL. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPES_HPP_INCLUDED #define __TYPES_HPP_INCLUDED extern "C" { #include "util/basetypes.h" }; #include "intermediate/operands/Operand.hpp" namespace ast { /** base type enumeration * @TODO maybe uniform array and record to composite? */ enum BaseType { BASE_TYPE_INTEGER, /**< (universal) integer based */ BASE_TYPE_REAL, /**< (universal) real (float) based */ BASE_TYPE_ARRAY, /**< array based */ BASE_TYPE_RECORD, /**< record based */ BASE_TYPE_RANGE_INT, /**< a (integer) range */ BASE_TYPE_RANGE_REAL, /**< a (float) range */ BASE_TYPE_ENUM, /**< an enumeration type */ BASE_TYPE_UNSET, /**< base type not yet set. */ }; /** resolve two base types. * @param left left operand * @param right right operand. * @return resolved type. */ enum BaseType operator &&(enum BaseType left, enum BaseType right); /** create an opcode type from a base type. * @param src base type enumeration to transform to an OpType. */ enum intermediate::OpType toOpType(enum BaseType src); }; /* namespace ast */ #endif /* __TYPES_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/NodeFactory.hpp0000664000175000017500000003650611243475123020352 0ustar potyrapotyra/* $Id: NodeFactory.hpp 4553 2009-08-21 10:43:31Z potyra $ * * NodeFactory: helper scripts for the Parser to create AST nodes, mainly * useful to not keep lots of c++ code out of the parser. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __NODE_FACTORY_HPP_INCLUDED #define __NODE_FACTORY_HPP_INCLUDED #include #include #include "frontend/ast/Expression.hpp" #include "frontend/ast/IfStat.hpp" #include "frontend/ast/LoopStat.hpp" #include "frontend/ast/ValDeclaration.hpp" #include "frontend/ast/CondalSigAssign.hpp" #include "frontend/ast/Location.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/reporting/SyntaxError.hpp" #include "frontend/visitor/TopDownVisitor.hpp" #include "frontend/ast/SignalDeclaration.hpp" #include "frontend/ast/ConstantDeclaration.hpp" #include "frontend/ast/Aggregate.hpp" #include "frontend/ast/SubtypeIndication.hpp" namespace ast { class Symbol; class SymbolTable; class NameLookup; /** The NodeFactory creates various AST nodes. It serves as a bridge between * the parser and the Syntax Tree. */ class NodeFactory { public: /** entity class of an attribute specification */ enum entityClassE { EC_ENTITY, EC_ARCHITECTURE, EC_CONFIGURATION, EC_PROCEDURE, EC_FUNCTION, EC_PACKAGE, EC_TYPE, EC_SUBTYPE, EC_CONSTANT, EC_SIGNAL, EC_VARIABLE, EC_COMPONENT, EC_LABEL, EC_LITERAL, EC_UNITS, EC_GROUP, EC_FILE }; /** storage helper class to unify range and index constraints. */ class Constraint { public: /** range constraint (if any) */ DiscreteRange *rangeConstraint; /** index constraint(s) (if any) */ std::list *indexConstraint; }; /** glue class to forward information about one identifier */ class Identifier { public: //! c'tor /** @param id string of the identifier * @param sym corresponding symbol (if any) */ Identifier( std::string *id, std::list cands ) : identifier(id), candidates(cands) {} /** string of the identifier */ std::string *identifier; /** list of candidate symbols */ std::list candidates; }; /** helper class for generating if_stats and condal signal * assignments. * */ struct IfHelperS { /** dummy c'tor: initialize members with NULL */ IfHelperS() : topstat(NULL), bottomElse(NULL) {} /** topmost if-statement of elsif part */ IfStat *topstat; /** reference to bottom most else part of elsif */ std::list **bottomElse; }; /** helper struct to flatten context items during parsing. */ struct ContextItemS { /** dummy c'tor: initialize members with NULL */ ContextItemS() : libClauses(NULL), useClauses(NULL) {} /** library clauses */ std::list *libClauses; /** use clauses */ std::list *useClauses; }; /** helper struct for type definitions. */ struct TypeDeclHelper { public: /** c'tor for enumeration types * @param et declared EnumerationType */ TypeDeclHelper( EnumerationType *et ) : enumType(et), typeDecl(NULL), conArrayBase(NULL), wasRecordType(false) {} /** c'tor for record types. * @param rt declared RecordType */ TypeDeclHelper( RecordType *rt ) : enumType(NULL), typeDecl(rt), conArrayBase(NULL), wasRecordType(true) {} /** c'tor for constraint array types. * The constraint array types declare an anonymous * unconstraint array and a subtype with an index constraint. * @param indexConstraint index constraint of the array. * @param elementType SubtypeIndication of the elements. * @param loc location of the array definition. * @param s SymbolTable instance. */ TypeDeclHelper( std::list *indexConstraint, SubtypeIndication *elementType, Location loc, SymbolTable &s); /** c'tor for other types. * @param other any other type declaration. */ TypeDeclHelper( TypeDeclaration *other ) : enumType(NULL), typeDecl(other), conArrayBase(NULL), wasRecordType(false) {} /** register type declaration to SymbolTable * @param symTab SymbolTable instance. * @param id identifier of the type declaration. */ void registerType( SymbolTable &symTab, NodeFactory::Identifier *id ) const; /** flatten to a list of SymbolDeclarations. */ std::list* flatten(void) const; /** enumeration type, in case one was declared. */ EnumerationType *enumType; /** any other type declaration. */ TypeDeclaration *typeDecl; /** corresponding anonymous base type of a constraint array */ TypeDeclaration *conArrayBase; /** was this type declaration a record type? */ bool wasRecordType; }; /** Helper function for parsing elsif statement lists * Attach a new ifStat from condition, thenStats to remainder. * If remainder doesn't exist, create a new IfHelperS. * * @param remainder the parent elsif remainder. * @param condition condition of the current elsif part. * @param thenStats then-statements of the current elsif part. * @param loc location of the elseif token. * * @return adjusted remainder or a new one if remainder doesn't exist * yet. */ static struct IfHelperS& createNestedElseIfs( struct IfHelperS *remainder, Expression* condition, std::list *thenStats, Location loc ); /** Helper function for parsing if_stats. * In case of elseIfs present, attach elseStats to bottom most * if-statement, and set elsIf part of current if statement to * else-part. * Otherwise build a "regular" if-then-else statement. * * @param condition condition of the current if-stat. * @param thenStats then-statement of the current if-stat. * @param elsIfs the elseIfs, which should already be nested. Struct * will get deleted from this function. * @param elseStats else statements of current if-stat. * @param loc location of the if token. * * @return parsed IfStat. */ static struct IfStat& createIfStat( Expression *condition, std::list *thenStats, struct IfHelperS* elsIfs, std::list *elseStats, Location loc ); /** Create a list of Signal declarations. * The contents of the parameters are reused in the result, so * the caller mustn't free them. * * @param ids list of Identifiers for each Signal. The list itself * isn't reused anywhere, so caller can free it. * @param mode access mode of signal (in, out, inout). * @param isBus is the signal tagged as bus? * @param varInit optional initializer of signal. * @param subtypeIndic subtype indication of signal. * @param loc location of the signal declaration. * @return list of ValDecls, caller must free it. */ static std::list& makeSignalDecls( std::list &ids, enum ValDeclaration::Mode mode, bool isBus, Expression *varInit, SubtypeIndication *subtypeIndic, Location loc ); /** Create a list of constant declarations. * The contents of the parameters are reused in the result, so * the caller mustn't free them. * * @param ids list of Identifiers for each Signal. The list itself * isn't reused anywhere, so caller can free it. * @param varInit optional initializer of constant. * @param subtypeIndic subtype indication of the constant. * @param loc Location of the constant declaration. * @return list of ValDecls, caller must free it. */ static std::list& makeConstantDecls( std::list &ids, Expression* varInit, SubtypeIndication *subtypeIndic, Location loc ); /** Create a list of Variable declarations. * The contents of the parameters are reused in the result, so * the caller mustn't free them. * * @param ids list of Identifiers for each Variable. The list itself * isn't reused anywhere, so caller can free it. * @param varInit optional initializer of variable. * @param subtypeIndic subtype indication of the variable. * @param loc Location of the variable declaration. * @return list of ValDecls, caller must free it. */ static std::list& makeVarDecls( std::list &ids, Expression *varInit, SubtypeIndication *subtypeIndic, Location loc ); /** Create a list of ValDeclaration declarations. * The contents of the parameters are reused in the result, so * the caller mustn't free them. * * This version is for function declarations. * * @param ids list of Identifiers for each Variable. The list itself * isn't reused anywhere, so caller can free it. * @param varInit optional initializer of variable. * @param cls object class that will determine if it's a * Signal, Variable or Constant. * @param subtypeIndic subtype indication of the element. * @param mode access mode of the ValDeclaration. * @param loc location in the source file. * @return list of ValDecls, caller must free it. */ static std::list& makeFuncInterfaceDecls( std::list &ids, Expression *varInit, enum ValDeclaration::Mode mode, enum ValDeclaration::ObjClass cls, SubtypeIndication *subtypeIndic, Location loc ); /** Create a list of ValDeclaration declarations. * The contents of the parameters are reused in the result, so * the caller mustn't free them. * * This version is for procedure declarations. * * @param ids list of Identifiers for each Variable. The list itself * isn't reused anywhere, so caller can free it. * @param varInit optional initializer of variable. * @param mode access mode (in/out/inout) * @param cls object class that will determine if it's a * Signal, Variable or Constant. * @param subtypeIndic subtype indication of the element. * @param loc location in the source file. * @return list of ValDecls, caller must free it. */ static std::list& makeProcInterfaceDecls( std::list &ids, Expression *varInit, enum ValDeclaration::Mode mode, enum ValDeclaration::ObjClass cls, SubtypeIndication *subtypeIndic, Location loc ); /** merge two context items. * The order will be all items from first context item first, then * items from second context item. * * @param first first context item. Parameter will be reused for * result, caller must free it. * @param second second context item. Parameter will get freed * during call. * @result merged context item. */ static struct ContextItemS& mergeContextItems( struct ContextItemS &first, struct ContextItemS &second ); /** correctly create a CondalSigAssign during parsing. * @param trg target value. Reused in result. * @param conds top IfStat or SigAssignStat. Reused in result. * @param loc location of assignment token. * @return created CondalSigAssign. Allocated node, caller should * free it once done with it. */ static CondalSigAssign& makeCondalSigAssign(Name &trg, SeqStat &conds, Location loc); /** create a list of record type elements. * @param idlist list of identifiers. * @param subtype subtype indication of element. * @param loc location of the first elements (FIXME) * @return list of elements. */ static std::list& makeRecordTypeElements( std::list &idlist, SubtypeIndication &subtype, Location loc); /** create the corresponding Aggregate from the give String Literal. * @param stringLit string literal. * @param loc Location of the string literal. * @param nl NameLookup instance. * @return the corresponding Aggregate or NULL if the string is a * null-string. */ static Aggregate* makeAggregateFromString( const std::string &stringLit, Location loc, const NameLookup &nl ); //! register all enumeration elements from an enumeration type /** @param etype EnumerationType for which all EnumerationElements * should get registered in the SymbolTable * @param symbolTable SymbolTable instance. * @param typeSym Symbol of the EnumerationType. */ static void registerEnumElems( const EnumerationType *etype, SymbolTable &symbolTable, Symbol *typeSym ); /** create an AttributeSpecification for the attribute denoted by * designator with initializer init and attribute the named * entities in entityList that fit the entity class classFilter * with it. * @param designator referred to attribute * @param entityList list of named entities to attribute * @param classFilter entity class * @param init initializer for the specification. * @param symTab SymbolTable instance. */ static AttributeSpecification * handleAttributeSpecs( SimpleName *designator, std::list entityList, enum entityClassE classFilter, Expression *init, const SymbolTable &symTab); /** safe upward cast a list of derived class U to a list of parent * class T. * @param l pointer to list of derived class pointers. Memory will * be reused as base class list. * @return list of base class pointers, type T * * Hint: if this function won't compile anywhere, just copy the * elements from the list, as this will always work (but is * slower). */ template static std::list* listCast(std::list *l); /** combine two lists of same type. * @param dest list where elements are getting push_back'ed. * @param source list which contains elements to add. */ template static void listCombine(std::list *dest, std::list *source); private: /** is the symbol sym of entityClass ec? * @param sym Symbol to check. * @param ec entity class * @return true if sym is of class ec. */ static bool isOfEntityClass(const Symbol &sym, enum entityClassE ec); //! very small visitor for attributing CondalSigAssign stats. /** This visitor will set the target for each SigAssignStat * that's part of a CondalSigAssign. */ class CondalSigAssignSetter : public TopDownVisitor { public: //! c'tor /** @param trg target that will get passed downwards. */ CondalSigAssignSetter(Name &trg) : target(trg) {} /** set target to SigAssignStat nodes. * @param node SigAssignStat that gets visited. */ virtual void visit(SigAssignStat &node); private: /** target that will be passed downwards. */ Name ⌖ }; }; }; /* namespace ast */ /* template definitions */ #include "frontend/ast/NodeFactory.tpp" #endif /* __NODE_FACTORY_HPP_INCLUDED */ fauhdlc-20130704/frontend/ast/RecordTypeElement.hpp0000664000175000017500000000377111137610234021521 0ustar potyrapotyra/* $Id: RecordTypeElement.hpp 4323 2009-01-27 13:48:12Z potyra $ * * RecordTypeElement: one subelement of a Record type. * * Copyright (C) 2007-2009 FAUmachine Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __RECORD_TYPE_ELEMENT_HPP_INCLUDED #define __RECORD_TYPE_ELEMENT_HPP_INCLUDED #include "frontend/ast/SymbolDeclaration.hpp" #include "frontend/ast/RecordType.hpp" #include "frontend/ast/SubtypeIndication.hpp" namespace ast { //! element of a VHDL Record type. /** This class represents one element of a VHDL Record type declaration. */ class RecordTypeElement : public SymbolDeclaration { public: //! c'tor /** @param id identifier of record element. * @param subtypeIndic subtype indication. * @param loc location of identifier. */ RecordTypeElement( std::string *id, SubtypeIndication *subtypeIndic, Location loc ) : SymbolDeclaration(id, loc), subtype(subtypeIndic), parent(NULL), offset(0) {} //! Accept a Visitor. /** All leaf AST nodes need to implement this method. * * @param visitor the Visitor that can visit this node. */ virtual void accept(Visitor& visitor) { visitor.visit(*this); } /** Put a textual representation of the AstNode on the stream. * @param stream stream to put the textual representation to. */ virtual void put(std::ostream &stream) const { assert(this->name); stream << *this->name << " : " << this->subtype; } /** subtype of element */ SubtypeIndication *subtype; /** parent record type. */ RecordType *parent; /** offset of the element (1st == 0, 2nd == 1, etc.) */ universal_integer offset; protected: /** Destructor */ virtual ~RecordTypeElement() { util::MiscUtil::terminate(subtype); } }; }; /* namespace ast */ #endif /* __RECORD_TYPE_ELEMENT_HPP_INCLUDED */