optimizing the performance of a pipelined processor

profileaassddff
sim.tar

sim/misc/Makefile

CC=gcc CFLAGS=-Wall -O1 -g LCFLAGS=-O1 LEX = flex YACC=bison LEXLIB = -lfl YAS=./yas all: yis yas hcl2c # These are implicit rules for making .yo files from .ys files. # E.g., make sum.yo .SUFFIXES: .ys .yo .ys.yo: $(YAS) $*.ys # These are the explicit rules for making yis yas and hcl2c and hcl2v yas-grammar.o: yas-grammar.c $(CC) $(LCFLAGS) -c yas-grammar.c yas-grammar.c: yas-grammar.lex $(LEX) yas-grammar.lex mv lex.yy.c yas-grammar.c isa.o: isa.c isa.h $(CC) $(CFLAGS) -c isa.c yas.o: yas.c yas.h isa.h $(CC) $(CFLAGS) -c yas.c yas: yas.o yas-grammar.o isa.o $(CC) $(CFLAGS) yas-grammar.o yas.o isa.o ${LEXLIB} -o yas yis.o: yis.c isa.h $(CC) $(CFLAGS) -c yis.c yis: yis.o isa.o $(CC) $(CFLAGS) yis.o isa.o -o yis hcl2c: hcl.tab.c lex.yy.c node.c outgen.c $(CC) $(LCFLAGS) node.c lex.yy.c hcl.tab.c outgen.c -o hcl2c hcl2v: hcl.tab.c lex.yy.c node.c outgen.c $(CC) $(LCFLAGS) -DVLOG node.c lex.yy.c hcl.tab.c outgen.c -o hcl2v hcl2u: hcl.tab.c lex.yy.c node.c outgen.c $(CC) $(LCFLAGS) -DUCLID node.c lex.yy.c hcl.tab.c outgen.c -o hcl2u lex.yy.c: hcl.lex $(LEX) hcl.lex hcl.tab.c: hcl.y $(YACC) -d hcl.y clean: rm -f *.o *.yo *.exe yis yas hcl2c mux4 *~ core.* rm -f hcl.tab.c hcl.tab.h lex.yy.c yas-grammar.c

sim/misc/README

/*********************************************************************** * Y86-64 Assembler, Instruction Simulator, and HCL translator * * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. * May not be used, modified, or copied without permission. ***********************************************************************/ This directory contains all of the source files for the following: YAS Y86-64 assembler YIS Y86-64 instruction level simulator HCL2C HCL to C translator HCL2V HCL to Verilog translator ********************* 1. Building the tools ********************* unix> make clean unix> make ******** 2. Files ******** Makefile Builds yas, yis, hcl2c, hcl2v README This file * Versions of Makefile in the student's distribution * (Instructor distribution only) Makefile-sim * Example programs for Part A of the CS:APP Architecture Lab examples.c C versions of three Y86-64 functions ans-copy.ys Solution copy function (instructor distribution only) ans-sum.ys Solution sum function (instructor distribution only) ans-rsum.ys Solution rsum function (instructor distribution only) * Instruction simulator code shared by yas, yis, ssim, ssim+, and psim isa.c isa.h * Files used to build the yas assembler yas The YAS binary yas.c yas source file and header file yas.h yas-grammar.lex Y86-64 lexical scanner spec yas-grammar.c Lexical scanner generated from yas-grammar.lex * Files used to build the yis instruction simulator yis The YIS binary yis.c yis source file * Files used to build the hcl2c translator hcl2c The HCL2C binary node.c auxiliary routines and header file node.h hcl.lex HCL lexical scanner spec lex.yy.c HCL lexical scanner generated from hcl.lex hcl.y HCL grammar hcl.tab.c HCL parser generated from hcl.y hcl.tab.h Token definitions * Example HCL programs used during the writing of the CS:APP book * (Instructor distribution only) frag.{hcl,c} mux4.{hcl,c} reg-file.{hcl,c}

sim/misc/node.c

/* Functions to generate C or Verilog code from HCL */ /* This file maintains a parse tree representation of expressions */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <ctype.h> #include "node.h" #include "outgen.h" #define MAXBUF 1024 void yyerror(const char *str); void yyserror(const char *str, char *other); /* For error reporting */ static char* show_expr(node_ptr expr); /* The symbol table */ #define SYM_LIM 100 static node_ptr sym_tab[2][SYM_LIM]; static int sym_count = 0; /* Optional simulator name */ char simname[MAXBUF] = ""; #ifdef UCLID int annotate = 0; /* Keep list of argument names encountered in node definition */ char *arg_names[SYM_LIM]; int arg_cnt = 0; #endif extern FILE *outfile; /* * usage - print helpful diagnostic information */ static void usage(char *name) { #ifdef VLOG fprintf(stderr, "Usage: %s [-h] < HCL_file > verilog_file\n", name); #else #ifdef UCLID fprintf(stderr, "Usage: %s [-ah] < HCL_file > uclid_file\n", name); fprintf(stderr, " -a Add define/use annotations\n"); #else /* !UCLID */ fprintf(stderr, "Usage: %s [-h][-n NAM] < HCL_file > C_file\n", name); #endif /* UCLID */ #endif /* VLOG */ fprintf(stderr, " -h Print this message\n"); fprintf(stderr, " -n NAM Specify processor name\n"); exit(0); } /* Initialization */ void init_node(int argc, char **argv) { int c; int max_column = 75; int first_indent = 4; int other_indents = 2; /* Parse the command line arguments */ while ((c = getopt(argc, argv, "hna")) != -1) { switch(c) { case 'h': usage(argv[0]); break; case 'n': /* Optional simulator name */ strcpy(simname, argv[optind]); break; #ifdef UCLID case 'a': annotate = 1; break; #endif default: printf("Invalid option '%c'\n", c); usage(argv[0]); break; } } #if !defined(VLOG) && !defined(UCLID) /* Define and initialize the simulator name */ if (!strcmp(simname, "")) printf("char simname[] = \"Y86-64 Processor\";\n"); else printf("char simname[] = \"Y86-64 Processor: %s\";\n", simname); #endif outgen_init(outfile, max_column, first_indent, other_indents); } static void add_symbol(node_ptr name, node_ptr val) { if (sym_count >= SYM_LIM) { yyerror("Symbol table limit exceeded"); return; } sym_tab[0][sym_count] = name; sym_tab[1][sym_count] = val; sym_count++; } static char *node_names[] = {"quote", "var", "num", "and", "or", "not", "comp", "ele", "case"}; static void show_node(node_ptr node) { printf("Node type: %s, Boolean ? %c, String value: %s\n", node_names[node->type], node->isbool ? 'Y':'N', node->sval); } void finish_node(int check_ref) { if (check_ref) { int i; for (i = 0; i < sym_count; i++) if (!sym_tab[0][i]->ref) { fprintf(stderr, "Warning, argument '%s' not referenced\n", sym_tab[0][i]->sval); } } } static node_ptr find_symbol(char *name) { int i; for (i = 0; i < sym_count; i++) { if (strcmp(name, sym_tab[0][i]->sval) == 0) { node_ptr result = sym_tab[1][i]; sym_tab[0][i]->ref++; return result; } } yyserror("Symbol %s not found", name); return NULL; } #ifdef UCLID /* See if string should be considered argument. Currently, omit strings that are all upper case */ static int is_arg(char *name) { int upper = 1; int c; while ((c=*name++) != '\0') upper = upper && isupper(c); return !upper; } /* See if string is part of current argument list */ static void check_for_arg(char *name) { int i; if (!is_arg(name)) return; for (i = 0; i < arg_cnt; i++) if (strcmp(arg_names[i], name) == 0) return; arg_names[arg_cnt++] = name; } #endif static node_ptr new_node(node_type_t t, int isbool, char *s, node_ptr a1, node_ptr a2) { node_ptr result = malloc(sizeof(node_rec)); result->type = t; result->isbool = isbool; result->sval = s; result->arg1 = a1; result->arg2 = a2; result->ref = 0; result->next = NULL; return result; } /* Concatenate two lists */ node_ptr concat(node_ptr n1, node_ptr n2) { node_ptr tail = n1; if (!n1) return n2; while (tail->next) tail = tail->next; tail->next = n2; return n1; } static void free_node(node_ptr n) { free(n->sval); free(n); } node_ptr make_quote(char *qstring) { /* Quoted string still has quotes around it */ int len = strlen(qstring)-2; char *sname = malloc(len+1); strncpy(sname, qstring+1, len); sname[len] = '\0'; return new_node(N_QUOTE, 0, sname, NULL, NULL); } node_ptr make_var(char *name) { char *sname = malloc(strlen(name)+1); strcpy(sname, name); /* Initially assume var is not Boolean */ return new_node(N_VAR, 0, sname, NULL, NULL); } node_ptr make_num(char *name) { char *sname = malloc(strlen(name)+1); strcpy(sname, name); return new_node(N_NUM, 0, sname, NULL, NULL); } void set_bool(node_ptr varnode) { if (!varnode) yyerror("Null node encountered"); varnode->isbool = 1; } /* Make sure argument is OK */ static int check_arg(node_ptr arg, int wantbool) { if (!arg) { yyerror("Null node encountered"); return 0; } if (arg->type == N_VAR) { node_ptr qval = find_symbol(arg->sval); if (!qval) { yyserror("Variable '%s' not found", arg->sval); return 0; } if (wantbool != qval->isbool) { if (wantbool) yyserror("Variable '%s' not Boolean", arg->sval); else yyserror("Variable '%s' not integer", arg->sval); return 0; } return 1; } if (arg->type == N_NUM) { if (wantbool && strcmp(arg->sval,"0") != 0 && strcmp(arg->sval,"1") != 0) { yyserror("Value '%s' not Boolean", arg->sval); return 0; } return 1; } if (wantbool && !arg->isbool) yyserror("Non Boolean argument '%s'", show_expr(arg)); if (!wantbool && arg->isbool) yyserror("Non integer argument '%s'", show_expr(arg)); return (wantbool == arg->isbool); } node_ptr make_not(node_ptr arg) { check_arg(arg, 1); return new_node(N_NOT, 1, "!", arg, NULL); } node_ptr make_and(node_ptr arg1, node_ptr arg2) { check_arg(arg1, 1); check_arg(arg2, 1); return new_node(N_AND, 1, "&", arg1, arg2); } node_ptr make_or(node_ptr arg1, node_ptr arg2) { check_arg(arg1, 1); check_arg(arg2, 1); return new_node(N_OR, 1, "|", arg1, arg2); } node_ptr make_comp(node_ptr op, node_ptr arg1, node_ptr arg2) { check_arg(arg1, 0); check_arg(arg2, 0); return new_node(N_COMP, 1, op->sval, arg1, arg2); } node_ptr make_ele(node_ptr arg1, node_ptr arg2) { node_ptr ele; check_arg(arg1, 0); for (ele = arg1; ele; ele = ele->next) check_arg(ele, 0); return new_node(N_ELE, 1, "in", arg1, arg2); } node_ptr make_case(node_ptr arg1, node_ptr arg2) { check_arg(arg1, 1); check_arg(arg2, 0); return new_node(N_CASE, 0, ":", arg1, arg2); } void insert_code(node_ptr qstring) { if (!qstring) yyerror("Null node"); else { #if !defined(VLOG) && !defined(UCLID) fputs(qstring->sval, outfile); fputs("\n", outfile); #endif } } void add_arg(node_ptr var, node_ptr qstring, int isbool) { if (!var || !qstring) { yyerror("Null node"); return; } add_symbol(var, qstring); if (isbool) { set_bool(var); set_bool(qstring); } } static char expr_buf[1024]; static int errlen = 0; #define MAXERRLEN 80 /* Recursively display expression for error reporting */ static void show_expr_helper(node_ptr expr) { switch(expr->type) { int len; node_ptr ele; case N_QUOTE: len = strlen(expr->sval) + 2; if (len + errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "'%s'", expr->sval); errlen += len; } break; case N_VAR: len = strlen(expr->sval); if (len + errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "%s", expr->sval); errlen += len; } break; case N_NUM: len = strlen(expr->sval); if (len + errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "%s", expr->sval); errlen += len; } break; case N_AND: if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "("); errlen+=1; show_expr_helper(expr->arg1); sprintf(expr_buf+errlen, " & "); errlen+=3; } if (errlen < MAXERRLEN) { show_expr_helper(expr->arg2); sprintf(expr_buf+errlen, ")"); errlen+=1; } break; case N_OR: if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "("); errlen+=1; show_expr_helper(expr->arg1); sprintf(expr_buf+errlen, " | "); errlen+=3; } if (errlen < MAXERRLEN) { show_expr_helper(expr->arg2); sprintf(expr_buf+errlen, ")"); errlen+=1; } break; case N_NOT: if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "!"); errlen+=1; show_expr_helper(expr->arg1); } break; case N_COMP: if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "("); errlen+=1; show_expr_helper(expr->arg1); sprintf(expr_buf+errlen, " %s ", expr->sval); errlen+=4; } if (errlen < MAXERRLEN) { show_expr_helper(expr->arg2); sprintf(expr_buf+errlen, ")"); errlen+=1; } break; case N_ELE: if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "("); errlen+=1; show_expr_helper(expr->arg1); sprintf(expr_buf+errlen, " in {"); errlen+=5; } for (ele = expr->arg2; ele; ele=ele->next) { if (errlen < MAXERRLEN) { show_expr_helper(ele); if (ele->next) { sprintf(expr_buf+errlen, ", "); errlen+=2; } } } if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "})"); errlen+=2; } break; case N_CASE: if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "[ "); errlen+=2; } for (ele = expr; errlen < MAXERRLEN && ele; ele=ele->next) { show_expr_helper(ele->arg1); sprintf(expr_buf+errlen, " : "); errlen += 3; show_expr_helper(ele->arg2); } if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, " ]"); errlen+=2; } break; default: if (errlen < MAXERRLEN) { sprintf(expr_buf+errlen, "??"); errlen+=2; } break; } } static char *show_expr(node_ptr expr) { errlen = 0; show_expr_helper(expr); if (errlen >= MAXERRLEN) sprintf(expr_buf+errlen, "..."); return expr_buf; } /* Recursively generate code for function */ static void gen_expr(node_ptr expr) { node_ptr ele; switch(expr->type) { case N_QUOTE: yyserror("Unexpected quoted string", expr->sval); break; case N_VAR: { node_ptr qstring = find_symbol(expr->sval); if (qstring) #if defined(VLOG) || defined(UCLID) outgen_print("%s", expr->sval); #else outgen_print("(%s)", qstring->sval); #endif else yyserror("Invalid variable '%s'", expr->sval); #ifdef UCLID check_for_arg(expr->sval); #endif } break; case N_NUM: #ifdef UCLID { long long int val = atoll(expr->sval); if (val < -1) outgen_print("pred^%d(CZERO)", -val); else if (val == -1) outgen_print("pred(CZERO)"); else if (val == 0) outgen_print("CZERO"); else if (val == 1) outgen_print("succ(CZERO)"); else outgen_print("succ^%d(CZERO)", val); } #else /* !UCLID */ fputs(expr->sval, outfile); #endif /* UCLID */ break; case N_AND: outgen_print("("); outgen_upindent(); gen_expr(expr->arg1); outgen_print(" & "); gen_expr(expr->arg2); outgen_print(")"); outgen_downindent(); break; case N_OR: outgen_print("("); outgen_upindent(); gen_expr(expr->arg1); outgen_print(" | "); gen_expr(expr->arg2); outgen_print(")"); outgen_downindent(); break; case N_NOT: #if defined(VLOG) || defined(UCLID) outgen_print("~"); #else outgen_print("!"); #endif gen_expr(expr->arg1); break; case N_COMP: outgen_print("("); outgen_upindent(); gen_expr(expr->arg1); #ifdef UCLID { char *cval = expr->sval; if (strcmp(cval, "==") == 0) cval = "="; outgen_print(" %s ", cval); } #else /* !UCLID */ outgen_print(" %s ", expr->sval); #endif /* UCLID */ gen_expr(expr->arg2); outgen_print(")"); outgen_downindent(); break; case N_ELE: outgen_print("("); outgen_upindent(); for (ele = expr->arg2; ele; ele=ele->next) { gen_expr(expr->arg1); #ifdef UCLID outgen_print(" = "); #else outgen_print(" == "); #endif gen_expr(ele); if (ele->next) #if defined(VLOG) || defined(UCLID) outgen_print(" | "); #else outgen_print(" || "); #endif } outgen_print(")"); outgen_downindent(); break; case N_CASE: #ifdef UCLID outgen_print("case"); outgen_terminate(); { /* Use this to keep track of last case when no default is given */ node_ptr last_arg2 = NULL; for (ele = expr; ele; ele=ele->next) { outgen_print(" "); if (ele->arg1->type == N_NUM && atoll(ele->arg1->sval) == 1) { outgen_print("default"); last_arg2 = NULL; } else { gen_expr(ele->arg1); last_arg2 = ele->arg2; } outgen_print(" : "); gen_expr(ele->arg2); outgen_print(";"); outgen_terminate(); } if (last_arg2) { /* Use final case as default */ outgen_print(" default : "); gen_expr(last_arg2); outgen_print(";"); outgen_terminate(); } } outgen_print(" esac"); #else /* !UCLID */ outgen_print("("); outgen_upindent(); int done = 0; for (ele = expr; ele && !done; ele=ele->next) { if (ele->arg1->type == N_NUM && atoll(ele->arg1->sval) == 1) { gen_expr(ele->arg2); done = 1; } else { gen_expr(ele->arg1); outgen_print(" ? "); gen_expr(ele->arg2); outgen_print(" : "); } } if (!done) outgen_print("0"); outgen_print(")"); outgen_downindent(); #endif break; default: yyerror("Unknown node type"); break; } } /* Generate code defining function for var */ void gen_funct(node_ptr var, node_ptr expr, int isbool) { if (!var || !expr) { yyerror("Null node"); return; } check_arg(expr, isbool); #ifdef VLOG outgen_print("assign %s = ", var->sval); outgen_terminate(); outgen_print(" "); gen_expr(expr); outgen_print(";"); outgen_terminate(); outgen_terminate(); #else /* !VLOG */ #ifdef UCLID if (annotate) { /* Print annotation information*/ outgen_print("(* $define %s *)", var->sval); outgen_terminate(); } outgen_print("%s := ", var->sval); outgen_terminate(); outgen_print(" "); if (isbool && expr->type == N_NUM) { outgen_print("%d", atoll(var->sval)); } else gen_expr(expr); outgen_print(";"); outgen_terminate(); if (annotate) { int i; outgen_print("(* $args"); for (i = 0; i < arg_cnt; i++) outgen_print("%c%s", i == 0 ? ' ' : ':', arg_names[i]); outgen_print(" *)"); outgen_terminate(); arg_cnt = 0; } outgen_terminate(); #else /* !UCLID */ /* Print function header */ outgen_print("long long gen_%s()", var->sval); outgen_terminate(); outgen_print("{"); outgen_terminate(); outgen_print(" return "); gen_expr(expr); outgen_print(";"); outgen_terminate(); outgen_print("}"); outgen_terminate(); outgen_terminate(); #endif /* UCLID */ #endif /* VLOG */ }

sim/misc/node.h

#ifndef NODE_H typedef enum { N_QUOTE, N_VAR, N_NUM, N_AND, N_OR, N_NOT, N_COMP, N_ELE, N_CASE } node_type_t; typedef struct NODE { node_type_t type; int isbool; /* Is this node a Boolean expression? */ char *sval; struct NODE *arg1; struct NODE *arg2; int ref; /* For var, how many times has it been referenced? */ struct NODE *next; } node_rec, *node_ptr; void init_node(int argc, char **argv); void finish_node(int check_ref); node_ptr make_quote(char *qstring); node_ptr make_var(char *name); node_ptr make_num(char *name); void set_bool(node_ptr varnode); node_ptr make_not(node_ptr arg); node_ptr make_and(node_ptr arg1, node_ptr arg2); node_ptr make_or(node_ptr arg1, node_ptr arg2); node_ptr make_comp(node_ptr op, node_ptr arg1, node_ptr arg2); node_ptr make_ele(node_ptr arg1, node_ptr arg2); node_ptr make_case(node_ptr arg1, node_ptr arg2); node_ptr concat(node_ptr n1, node_ptr n2); void insert_code(node_ptr qstring); void add_arg(node_ptr var, node_ptr qstring, int isbool); void gen_funct(node_ptr var, node_ptr expr, int isbool); #define NODE_H #endif

sim/misc/outgen.c

#include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include "outgen.h" /* Output generator that ensures no line exceeds specified number of columns */ #define STRING_LENGTH 1024 FILE *outfile = NULL; int max_column = 80; int first_indent = 4; int other_indents = 2; int cur_pos = 0; int indent = 0; /* Controlling parameters */ void outgen_init(FILE *arg_outfile, int arg_max_column, int arg_first_indent, int arg_other_indents) { outfile = arg_outfile; max_column = arg_max_column; first_indent = arg_first_indent; other_indents = arg_other_indents; cur_pos = 0; indent = first_indent; } static void print_token(char *string) { if (outfile == NULL) outfile = stdout; int len = strlen(string); int i; if (len+cur_pos > max_column) { fprintf(outfile, "\n"); for (i = 0; i < indent; i++) fprintf(outfile, " "); cur_pos = indent; } fprintf(outfile, "%s", string); cur_pos += len; } /* Terminate statement and reset indentations */ void outgen_terminate() { printf("\n"); cur_pos = 0; indent = first_indent; } /* Output generator printing */ void outgen_print(char *fmt, ...) { char buf[STRING_LENGTH]; va_list argp; va_start(argp, fmt); vsprintf(buf, fmt, argp); va_end(argp); print_token(buf); } /* Increase indentation level */ void outgen_upindent() { indent += other_indents; } /* Decrease indentation level */ void outgen_downindent() { indent -= other_indents; }

sim/misc/outgen.h

/* Output generator that ensures no line exceeds specified number of columns */ /* Controlling parameters */ void outgen_init(FILE *outfile, int max_column, int first_indent, int other_indents); /* Terminate statement and reset indentations */ void outgen_terminate(); /* Output generator printing */ void outgen_print(char *fmt, ...); /* Increase indentation level */ void outgen_upindent(); /* Decrease indentation level */ void outgen_downindent();

sim/misc/mux4.hcl

#/* $begin sim-mux4-raw-hcl */ ## Simple example of an HCL file. ## This file can be converted to C using hcl2c, and then compiled. ## In this example, we will generate the MUX4 circuit shown in ## Section SLASHrefLBRACKsect:arch:hclsetRBRACK. It consists of a control block that generates ## bit-level signals s1 and s0 from the input signal code, ## and then uses these signals to control a 4-way multiplexor ## with data inputs A, B, C, and D. ## This code is embedded in a C program that reads ## the values of code, A, B, C, and D from the command line ## and then prints the circuit output ## Information that is inserted verbatim into the C file quote '#include <stdio.h>' quote '#include <stdlib.h>' quote 'long long code_val, s0_val, s1_val;' quote 'char **data_names;' ## Declarations of signals used in the HCL description and ## the corresponding C expressions. boolsig s0 's0_val' boolsig s1 's1_val' wordsig code 'code_val' wordsig A 'atoll(data_names[0])' wordsig B 'atoll(data_names[1])' wordsig C 'atoll(data_names[2])' wordsig D 'atoll(data_names[3])' ## HCL descriptions of the logic blocks quote '/* $begin sim-mux4-s1-c */' bool s1 = code in { 2, 3 }; quote '/* $end sim-mux4-s1-c */' bool s0 = code in { 1, 3 }; word Out4 = [ !s1 && !s0 : A; # 00 !s1 : B; # 01 !s0 : C; # 10 1 : D; # 11 ]; ## More information inserted verbatim into the C code to ## compute the values and print the output quote '/* $begin sim-mux4-main-c */' quote 'int main(int argc, char *argv[]) {' quote ' data_names = argv+2;' quote ' code_val = atoll(argv[1]);' quote ' s1_val = gen_s1();' quote ' s0_val = gen_s0();' quote ' printf("Out = %lld\n", gen_Out4());' quote ' return 0;' quote '}' quote '/* $end sim-mux4-main-c */' #/* $end sim-mux4-raw-hcl */

sim/misc/isa.h

/* Instruction Set definition for Y86-64 Architecture */ /* Revisions: 2013-10-25: Extended all data widths and addresses to 64 bits Changed all 'l' instructions to 'q' Changed registers name from e-form to r-form Added registers %r8 to %r14 2009-03-11: Changed RNONE to be 0xF Changed J_XX and jump_t to C_XX and cond_t; take_branch to cond_holds Expanded RRMOVL to include conditional moves */ /**************** Registers *************************/ /* REG_NONE is a special one to indicate no register */ typedef enum { REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI, REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_NONE=0xF, REG_ERR } reg_id_t; /* Find register ID given its name */ reg_id_t find_register(char *name); /* Return name of register given its ID */ char *reg_name(reg_id_t id); /**************** Instruction Encoding **************/ /* Different argument types */ typedef enum { R_ARG, M_ARG, I_ARG, NO_ARG } arg_t; /* Different instruction types */ typedef enum { I_HALT, I_NOP, I_RRMOVQ, I_IRMOVQ, I_RMMOVQ, I_MRMOVQ, I_ALU, I_JMP, I_CALL, I_RET, I_PUSHQ, I_POPQ, I_IADDQ, I_POP2 } itype_t; /* Different ALU operations */ typedef enum { A_ADD, A_SUB, A_AND, A_XOR, A_NONE } alu_t; /* Default function code */ typedef enum { F_NONE } fun_t; /* Return name of operation given its ID */ char op_name(alu_t op); /* Different Jump conditions */ typedef enum { C_YES, C_LE, C_L, C_E, C_NE, C_GE, C_G } cond_t; /* Pack itype and function into single byte */ #define HPACK(hi,lo) ((((hi)&0xF)<<4)|((lo)&0xF)) /* Unpack byte */ #define HI4(byte) (((byte)>>4)&0xF) #define LO4(byte) ((byte)&0xF) /* Get the opcode out of one byte instruction field */ #define GET_ICODE(instr) HI4(instr) /* Get the ALU/JMP function out of one byte instruction field */ #define GET_FUN(instr) LO4(instr) /* Return name of instruction given it's byte encoding */ char *iname(int instr); /**************** Truth Values **************/ typedef enum { FALSE, TRUE } bool_t; /* Table used to encode information about instructions */ typedef struct { char *name; unsigned char code; /* Byte code for instruction+op */ int bytes; arg_t arg1; int arg1pos; int arg1hi; /* 0/1 for register argument, # bytes for allocation */ arg_t arg2; int arg2pos; int arg2hi; /* 0/1 */ } instr_t, *instr_ptr; instr_ptr find_instr(char *name); /* Return invalid instruction for error handling purposes */ instr_ptr bad_instr(); /*********** Implementation of Memory *****************/ typedef unsigned char byte_t; typedef long long int word_t; typedef long long unsigned uword_t; /* Represent a memory as an array of bytes */ typedef struct { int len; word_t maxaddr; byte_t *contents; } mem_rec, *mem_t; /* Create a memory with len bytes */ mem_t init_mem(int len); void free_mem(mem_t m); /* Set contents of memory to 0 */ void clear_mem(mem_t m); /* Make a copy of a memory */ mem_t copy_mem(mem_t oldm); /* Print the differences between two memories */ bool_t diff_mem(mem_t oldm, mem_t newm, FILE *outfile); /* How big should the memory be? */ #ifdef BIG_MEM #define MEM_SIZE (1<<16) #else #define MEM_SIZE (1<<13) #endif /*** In the following functions, a return value of 1 means success ***/ /* Load memory from .yo file. Return number of bytes read */ int load_mem(mem_t m, FILE *infile, int report_error); /* Get byte from memory */ bool_t get_byte_val(mem_t m, word_t pos, byte_t *dest); /* Get 8 bytes from memory */ bool_t get_word_val(mem_t m, word_t pos, word_t *dest); /* Set byte in memory */ bool_t set_byte_val(mem_t m, word_t pos, byte_t val); /* Set 8 bytes in memory */ bool_t set_word_val(mem_t m, word_t pos, word_t val); /* Print contents of memory */ void dump_memory(FILE *outfile, mem_t m, word_t pos, int cnt); /********** Implementation of Register File *************/ mem_t init_reg(); void free_reg(); /* Make a copy of a register file */ mem_t copy_reg(mem_t oldr); /* Print the differences between two register files */ bool_t diff_reg(mem_t oldr, mem_t newr, FILE *outfile); word_t get_reg_val(mem_t r, reg_id_t id); void set_reg_val(mem_t r, reg_id_t id, word_t val); void dump_reg(FILE *outfile, mem_t r); /* **************** ALU Function **********************/ /* Compute ALU operation */ word_t compute_alu(alu_t op, word_t arg1, word_t arg2); typedef unsigned char cc_t; #define GET_ZF(cc) (((cc) >> 2)&0x1) #define GET_SF(cc) (((cc) >> 1)&0x1) #define GET_OF(cc) (((cc) >> 0)&0x1) #define PACK_CC(z,s,o) (((z)<<2)|((s)<<1)|((o)<<0)) #define DEFAULT_CC PACK_CC(1,0,0) /* Compute condition code. */ cc_t compute_cc(alu_t op, word_t arg1, word_t arg2); /* Generated printed form of condition code */ char *cc_name(cc_t c); /* **************** Status types *******************/ typedef enum {STAT_BUB, STAT_AOK, STAT_HLT, STAT_ADR, STAT_INS, STAT_PIP } stat_t; /* Describe Status */ char *stat_name(stat_t e); /* **************** ISA level implementation *********/ typedef struct { word_t pc; mem_t r; mem_t m; cc_t cc; } state_rec, *state_ptr; state_ptr new_state(int memlen); void free_state(state_ptr s); state_ptr copy_state(state_ptr s); bool_t diff_state(state_ptr olds, state_ptr news, FILE *outfile); /* Determine if condition satisified */ bool_t cond_holds(cc_t cc, cond_t bcond); /* Execute single instruction. Return status. */ stat_t step_state(state_ptr s, FILE *error_file); /************************ Interface Functions *************/ #ifdef HAS_GUI void report_line(word_t line_no, word_t addr, char *hexcode, char *line); void signal_register_update(reg_id_t r, word_t val); #endif

sim/misc/isa.c

#include <stdlib.h> #include <ctype.h> #include <stdio.h> #include <string.h> #include "isa.h" /* Are we running in GUI mode? */ extern int gui_mode; /* Bytes Per Line = Block size of memory */ #define BPL 32 struct { char *name; int id; } reg_table[REG_ERR+1] = { {"%rax", REG_RAX}, {"%rcx", REG_RCX}, {"%rdx", REG_RDX}, {"%rbx", REG_RBX}, {"%rsp", REG_RSP}, {"%rbp", REG_RBP}, {"%rsi", REG_RSI}, {"%rdi", REG_RDI}, {"%r8", REG_R8}, {"%r9", REG_R9}, {"%r10", REG_R10}, {"%r11", REG_R11}, {"%r12", REG_R12}, {"%r13", REG_R13}, {"%r14", REG_R14}, {"----", REG_NONE}, {"----", REG_ERR} }; reg_id_t find_register(char *name) { int i; for (i = 0; i < REG_NONE; i++) if (!strcmp(name, reg_table[i].name)) return reg_table[i].id; return REG_ERR; } char *reg_name(reg_id_t id) { if (id >= 0 && id < REG_NONE) return reg_table[id].name; else return reg_table[REG_NONE].name; } /* Is the given register ID a valid program register? */ int reg_valid(reg_id_t id) { return id >= 0 && id < REG_NONE && reg_table[id].id == id; } instr_t instruction_set[] = { {"nop", HPACK(I_NOP, F_NONE), 1, NO_ARG, 0, 0, NO_ARG, 0, 0 }, {"halt", HPACK(I_HALT, F_NONE), 1, NO_ARG, 0, 0, NO_ARG, 0, 0 }, {"rrmovq", HPACK(I_RRMOVQ, F_NONE), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, /* Conditional move instructions are variants of RRMOVQ */ {"cmovle", HPACK(I_RRMOVQ, C_LE), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"cmovl", HPACK(I_RRMOVQ, C_L), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"cmove", HPACK(I_RRMOVQ, C_E), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"cmovne", HPACK(I_RRMOVQ, C_NE), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"cmovge", HPACK(I_RRMOVQ, C_GE), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"cmovg", HPACK(I_RRMOVQ, C_G), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, /* arg1hi indicates number of bytes */ {"irmovq", HPACK(I_IRMOVQ, F_NONE), 10, I_ARG, 2, 8, R_ARG, 1, 0 }, {"rmmovq", HPACK(I_RMMOVQ, F_NONE), 10, R_ARG, 1, 1, M_ARG, 1, 0 }, {"mrmovq", HPACK(I_MRMOVQ, F_NONE), 10, M_ARG, 1, 0, R_ARG, 1, 1 }, {"addq", HPACK(I_ALU, A_ADD), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"subq", HPACK(I_ALU, A_SUB), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"andq", HPACK(I_ALU, A_AND), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, {"xorq", HPACK(I_ALU, A_XOR), 2, R_ARG, 1, 1, R_ARG, 1, 0 }, /* arg1hi indicates number of bytes */ {"jmp", HPACK(I_JMP, C_YES), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"jle", HPACK(I_JMP, C_LE), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"jl", HPACK(I_JMP, C_L), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"je", HPACK(I_JMP, C_E), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"jne", HPACK(I_JMP, C_NE), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"jge", HPACK(I_JMP, C_GE), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"jg", HPACK(I_JMP, C_G), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"call", HPACK(I_CALL, F_NONE), 9, I_ARG, 1, 8, NO_ARG, 0, 0 }, {"ret", HPACK(I_RET, F_NONE), 1, NO_ARG, 0, 0, NO_ARG, 0, 0 }, {"pushq", HPACK(I_PUSHQ, F_NONE) , 2, R_ARG, 1, 1, NO_ARG, 0, 0 }, {"popq", HPACK(I_POPQ, F_NONE) , 2, R_ARG, 1, 1, NO_ARG, 0, 0 }, {"iaddq", HPACK(I_IADDQ, F_NONE), 10, I_ARG, 2, 8, R_ARG, 1, 0 }, /* this is just a hack to make the I_POP2 code have an associated name */ {"pop2", HPACK(I_POP2, F_NONE) , 0, NO_ARG, 0, 0, NO_ARG, 0, 0 }, /* For allocation instructions, arg1hi indicates number of bytes */ {".byte", 0x00, 1, I_ARG, 0, 1, NO_ARG, 0, 0 }, {".word", 0x00, 2, I_ARG, 0, 2, NO_ARG, 0, 0 }, {".long", 0x00, 4, I_ARG, 0, 4, NO_ARG, 0, 0 }, {".quad", 0x00, 8, I_ARG, 0, 8, NO_ARG, 0, 0 }, {NULL, 0 , 0, NO_ARG, 0, 0, NO_ARG, 0, 0 } }; instr_t invalid_instr = {"XXX", 0 , 0, NO_ARG, 0, 0, NO_ARG, 0, 0 }; instr_ptr find_instr(char *name) { int i; for (i = 0; instruction_set[i].name; i++) if (strcmp(instruction_set[i].name,name) == 0) return &instruction_set[i]; return NULL; } /* Return name of instruction given its encoding */ char *iname(int instr) { int i; for (i = 0; instruction_set[i].name; i++) { if (instr == instruction_set[i].code) return instruction_set[i].name; } return "<bad>"; } instr_ptr bad_instr() { return &invalid_instr; } mem_t init_mem(int len) { mem_t result = (mem_t) malloc(sizeof(mem_rec)); len = ((len+BPL-1)/BPL)*BPL; result->len = len; result->contents = (byte_t *) calloc(len, 1); return result; } void clear_mem(mem_t m) { memset(m->contents, 0, m->len); } void free_mem(mem_t m) { free((void *) m->contents); free((void *) m); } mem_t copy_mem(mem_t oldm) { mem_t newm = init_mem(oldm->len); memcpy(newm->contents, oldm->contents, oldm->len); return newm; } bool_t diff_mem(mem_t oldm, mem_t newm, FILE *outfile) { word_t pos; int len = oldm->len; bool_t diff = FALSE; if (newm->len < len) len = newm->len; for (pos = 0; (!diff || outfile) && pos < len; pos += 8) { word_t ov = 0; word_t nv = 0; get_word_val(oldm, pos, &ov); get_word_val(newm, pos, &nv); if (nv != ov) { diff = TRUE; if (outfile) fprintf(outfile, "0x%.4llx:\t0x%.16llx\t0x%.16llx\n", pos, ov, nv); } } return diff; } int hex2dig(char c) { if (isdigit((int)c)) return c - '0'; if (isupper((int)c)) return c - 'A' + 10; else return c - 'a' + 10; } #define LINELEN 4096 int load_mem(mem_t m, FILE *infile, int report_error) { /* Read contents of .yo file */ char buf[LINELEN]; char c, ch, cl; int byte_cnt = 0; int lineno = 0; word_t bytepos = 0; #ifdef HAS_GUI int empty_line = 1; int addr = 0; char hexcode[21]; /* For display */ int line_no = 0; char line[LINELEN]; int index = 0; #endif /* HAS_GUI */ while (fgets(buf, LINELEN, infile)) { int cpos = 0; #ifdef HAS_GUI empty_line = 1; #endif lineno++; /* Skip white space */ while (isspace((int)buf[cpos])) cpos++; if (buf[cpos] != '0' || (buf[cpos+1] != 'x' && buf[cpos+1] != 'X')) continue; /* Skip this line */ cpos+=2; /* Get address */ bytepos = 0; while (isxdigit((int)(c=buf[cpos]))) { cpos++; bytepos = bytepos*16 + hex2dig(c); } while (isspace((int)buf[cpos])) cpos++; if (buf[cpos++] != ':') { if (report_error) { fprintf(stderr, "Error reading file. Expected colon\n"); fprintf(stderr, "Line %d:%s\n", lineno, buf); fprintf(stderr, "Reading '%c' at position %d\n", buf[cpos], cpos); } return 0; } #ifdef HAS_GUI addr = bytepos; index = 0; #endif while (isspace((int)buf[cpos])) cpos++; /* Get code */ while (isxdigit((int)(ch=buf[cpos++])) && isxdigit((int)(cl=buf[cpos++]))) { byte_t byte = 0; if (bytepos >= m->len) { if (report_error) { fprintf(stderr, "Error reading file. Invalid address. 0x%llx\n", bytepos); fprintf(stderr, "Line %d:%s\n", lineno, buf); } return 0; } byte = hex2dig(ch)*16+hex2dig(cl); m->contents[bytepos++] = byte; byte_cnt++; #ifdef HAS_GUI empty_line = 0; hexcode[index++] = ch; hexcode[index++] = cl; #endif } #ifdef HAS_GUI /* Fill rest of hexcode with blanks. Needs to be 2x longest instruction */ for (; index < 20; index++) hexcode[index] = ' '; hexcode[index] = '\0'; if (gui_mode) { /* Now get the rest of the line */ while (isspace((int)buf[cpos])) cpos++; cpos++; /* Skip over '|' */ index = 0; while ((c = buf[cpos++]) != '\0' && c != '\n') { line[index++] = c; } line[index] = '\0'; if (!empty_line) report_line(line_no++, addr, hexcode, line); } #endif /* HAS_GUI */ } return byte_cnt; } bool_t get_byte_val(mem_t m, word_t pos, byte_t *dest) { if (pos < 0 || pos >= m->len) return FALSE; *dest = m->contents[pos]; return TRUE; } bool_t get_word_val(mem_t m, word_t pos, word_t *dest) { int i; word_t val; if (pos < 0 || pos + 8 > m->len) return FALSE; val = 0; for (i = 0; i < 8; i++) { word_t b = m->contents[pos+i] & 0xFF; val = val | (b <<(8*i)); } *dest = val; return TRUE; } bool_t set_byte_val(mem_t m, word_t pos, byte_t val) { if (pos < 0 || pos >= m->len) return FALSE; m->contents[pos] = val; return TRUE; } bool_t set_word_val(mem_t m, word_t pos, word_t val) { int i; if (pos < 0 || pos + 8 > m->len) return FALSE; for (i = 0; i < 8; i++) { m->contents[pos+i] = (byte_t) val & 0xFF; val >>= 8; } return TRUE; } void dump_memory(FILE *outfile, mem_t m, word_t pos, int len) { int i, j; while (pos % BPL) { pos --; len ++; } len = ((len+BPL-1)/BPL)*BPL; if (pos+len > m->len) len = m->len-pos; for (i = 0; i < len; i+=BPL) { word_t val = 0; fprintf(outfile, "0x%.4llx:", pos+i); for (j = 0; j < BPL; j+= 8) { get_word_val(m, pos+i+j, &val); fprintf(outfile, " %.16llx", val); } } } mem_t init_reg() { return init_mem(128); } void free_reg(mem_t r) { free_mem(r); } mem_t copy_reg(mem_t oldr) { return copy_mem(oldr); } bool_t diff_reg(mem_t oldr, mem_t newr, FILE *outfile) { word_t pos; int len = oldr->len; bool_t diff = FALSE; if (newr->len < len) len = newr->len; for (pos = 0; (!diff || outfile) && pos < len; pos += 8) { word_t ov = 0; word_t nv = 0; get_word_val(oldr, pos, &ov); get_word_val(newr, pos, &nv); if (nv != ov) { diff = TRUE; if (outfile) fprintf(outfile, "%s:\t0x%.16llx\t0x%.16llx\n", reg_table[pos/8].name, ov, nv); } } return diff; } word_t get_reg_val(mem_t r, reg_id_t id) { word_t val = 0; if (id >= REG_NONE) return 0; get_word_val(r,id*8, &val); return val; } void set_reg_val(mem_t r, reg_id_t id, word_t val) { if (id < REG_NONE) { set_word_val(r,id*8,val); #ifdef HAS_GUI if (gui_mode) { signal_register_update(id, val); } #endif /* HAS_GUI */ } } void dump_reg(FILE *outfile, mem_t r) { reg_id_t id; for (id = 0; reg_valid(id); id++) { fprintf(outfile, " %s ", reg_table[id].name); } fprintf(outfile, "\n"); for (id = 0; reg_valid(id); id++) { word_t val = 0; get_word_val(r, id*8, &val); fprintf(outfile, " %llx", val); } fprintf(outfile, "\n"); } struct { char symbol; int id; } alu_table[A_NONE+1] = { {'+', A_ADD}, {'-', A_SUB}, {'&', A_AND}, {'^', A_XOR}, {'?', A_NONE} }; char op_name(alu_t op) { if (op < A_NONE) return alu_table[op].symbol; else return alu_table[A_NONE].symbol; } word_t compute_alu(alu_t op, word_t argA, word_t argB) { word_t val; switch(op) { case A_ADD: val = argA+argB; break; case A_SUB: val = argB-argA; break; case A_AND: val = argA&argB; break; case A_XOR: val = argA^argB; break; default: val = 0; } return val; } cc_t compute_cc(alu_t op, word_t argA, word_t argB) { word_t val = compute_alu(op, argA, argB); bool_t zero = (val == 0); bool_t sign = ((word_t)val < 0); bool_t ovf; switch(op) { case A_ADD: ovf = (((word_t) argA < 0) == ((word_t) argB < 0)) && (((word_t) val < 0) != ((word_t) argA < 0)); break; case A_SUB: ovf = (((word_t) argA > 0) == ((word_t) argB < 0)) && (((word_t) val < 0) != ((word_t) argB < 0)); break; case A_AND: case A_XOR: ovf = FALSE; break; default: ovf = FALSE; } return PACK_CC(zero,sign,ovf); } char *cc_names[8] = { "Z=0 S=0 O=0", "Z=0 S=0 O=1", "Z=0 S=1 O=0", "Z=0 S=1 O=1", "Z=1 S=0 O=0", "Z=1 S=0 O=1", "Z=1 S=1 O=0", "Z=1 S=1 O=1"}; char *cc_name(cc_t c) { int ci = c; if (ci < 0 || ci > 7) return "???????????"; else return cc_names[c]; } /* Status types */ char *stat_names[] = { "BUB", "AOK", "HLT", "ADR", "INS", "PIP" }; char *stat_name(stat_t e) { if (e < 0 || e > STAT_PIP) return "Invalid Status"; return stat_names[e]; } /**************** Implementation of ISA model ************************/ state_ptr new_state(int memlen) { state_ptr result = (state_ptr) malloc(sizeof(state_rec)); result->pc = 0; result->r = init_reg(); result->m = init_mem(memlen); result->cc = DEFAULT_CC; return result; } void free_state(state_ptr s) { free_reg(s->r); free_mem(s->m); free((void *) s); } state_ptr copy_state(state_ptr s) { state_ptr result = (state_ptr) malloc(sizeof(state_rec)); result->pc = s->pc; result->r = copy_reg(s->r); result->m = copy_mem(s->m); result->cc = s->cc; return result; } bool_t diff_state(state_ptr olds, state_ptr news, FILE *outfile) { bool_t diff = FALSE; if (olds->pc != news->pc) { diff = TRUE; if (outfile) { fprintf(outfile, "pc:\t0x%.16llx\t0x%.16llx\n", olds->pc, news->pc); } } if (olds->cc != news->cc) { diff = TRUE; if (outfile) { fprintf(outfile, "cc:\t%s\t%s\n", cc_name(olds->cc), cc_name(news->cc)); } } if (diff_reg(olds->r, news->r, outfile)) diff = TRUE; if (diff_mem(olds->m, news->m, outfile)) diff = TRUE; return diff; } /* Branch logic */ bool_t cond_holds(cc_t cc, cond_t bcond) { bool_t zf = GET_ZF(cc); bool_t sf = GET_SF(cc); bool_t of = GET_OF(cc); bool_t jump = FALSE; switch(bcond) { case C_YES: jump = TRUE; break; case C_LE: jump = (sf^of)|zf; break; case C_L: jump = sf^of; break; case C_E: jump = zf; break; case C_NE: jump = zf^1; break; case C_GE: jump = sf^of^1; break; case C_G: jump = (sf^of^1)&(zf^1); break; default: jump = FALSE; break; } return jump; } /* Execute single instruction. Return status. */ stat_t step_state(state_ptr s, FILE *error_file) { word_t argA, argB; byte_t byte0 = 0; byte_t byte1 = 0; itype_t hi0; alu_t lo0; reg_id_t hi1 = REG_NONE; reg_id_t lo1 = REG_NONE; bool_t ok1 = TRUE; word_t cval = 0; word_t okc = TRUE; word_t val, dval; bool_t need_regids; bool_t need_imm; word_t ftpc = s->pc; /* Fall-through PC */ if (!get_byte_val(s->m, ftpc, &byte0)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } ftpc++; hi0 = HI4(byte0); lo0 = LO4(byte0); need_regids = (hi0 == I_RRMOVQ || hi0 == I_ALU || hi0 == I_PUSHQ || hi0 == I_POPQ || hi0 == I_IRMOVQ || hi0 == I_RMMOVQ || hi0 == I_MRMOVQ || hi0 == I_IADDQ); if (need_regids) { ok1 = get_byte_val(s->m, ftpc, &byte1); ftpc++; hi1 = HI4(byte1); lo1 = LO4(byte1); } need_imm = (hi0 == I_IRMOVQ || hi0 == I_RMMOVQ || hi0 == I_MRMOVQ || hi0 == I_JMP || hi0 == I_CALL || hi0 == I_IADDQ); if (need_imm) { okc = get_word_val(s->m, ftpc, &cval); ftpc += 8; } switch (hi0) { case I_NOP: s->pc = ftpc; break; case I_HALT: return STAT_HLT; break; case I_RRMOVQ: /* Both unconditional and conditional moves */ if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!reg_valid(hi1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, hi1); return STAT_INS; } if (!reg_valid(lo1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, lo1); return STAT_INS; } val = get_reg_val(s->r, hi1); if (cond_holds(s->cc, lo0)) set_reg_val(s->r, lo1, val); s->pc = ftpc; break; case I_IRMOVQ: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!okc) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address", s->pc); return STAT_INS; } if (!reg_valid(lo1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, lo1); return STAT_INS; } set_reg_val(s->r, lo1, cval); s->pc = ftpc; break; case I_RMMOVQ: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!okc) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_INS; } if (!reg_valid(hi1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, hi1); return STAT_INS; } if (reg_valid(lo1)) cval += get_reg_val(s->r, lo1); val = get_reg_val(s->r, hi1); if (!set_word_val(s->m, cval, val)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid data address 0x%llx\n", s->pc, cval); return STAT_ADR; } s->pc = ftpc; break; case I_MRMOVQ: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!okc) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction addres\n", s->pc); return STAT_INS; } if (!reg_valid(hi1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, hi1); return STAT_INS; } if (reg_valid(lo1)) cval += get_reg_val(s->r, lo1); if (!get_word_val(s->m, cval, &val)) return STAT_ADR; set_reg_val(s->r, hi1, val); s->pc = ftpc; break; case I_ALU: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } argA = get_reg_val(s->r, hi1); argB = get_reg_val(s->r, lo1); val = compute_alu(lo0, argA, argB); set_reg_val(s->r, lo1, val); s->cc = compute_cc(lo0, argA, argB); s->pc = ftpc; break; case I_JMP: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!okc) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (cond_holds(s->cc, lo0)) s->pc = cval; else s->pc = ftpc; break; case I_CALL: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!okc) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } val = get_reg_val(s->r, REG_RSP) - 8; set_reg_val(s->r, REG_RSP, val); if (!set_word_val(s->m, val, ftpc)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid stack address 0x%llx\n", s->pc, val); return STAT_ADR; } s->pc = cval; break; case I_RET: /* Return Instruction. Pop address from stack */ dval = get_reg_val(s->r, REG_RSP); if (!get_word_val(s->m, dval, &val)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid stack address 0x%llx\n", s->pc, dval); return STAT_ADR; } set_reg_val(s->r, REG_RSP, dval + 8); s->pc = val; break; case I_PUSHQ: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!reg_valid(hi1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, hi1); return STAT_INS; } val = get_reg_val(s->r, hi1); dval = get_reg_val(s->r, REG_RSP) - 8; set_reg_val(s->r, REG_RSP, dval); if (!set_word_val(s->m, dval, val)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid stack address 0x%llx\n", s->pc, dval); return STAT_ADR; } s->pc = ftpc; break; case I_POPQ: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!reg_valid(hi1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, hi1); return STAT_INS; } dval = get_reg_val(s->r, REG_RSP); set_reg_val(s->r, REG_RSP, dval+8); if (!get_word_val(s->m, dval, &val)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid stack address 0x%llx\n", s->pc, dval); return STAT_ADR; } set_reg_val(s->r, hi1, val); s->pc = ftpc; break; case I_IADDQ: if (!ok1) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address\n", s->pc); return STAT_ADR; } if (!okc) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction address", s->pc); return STAT_INS; } if (!reg_valid(lo1)) { if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid register ID 0x%.1x\n", s->pc, lo1); return STAT_INS; } argB = get_reg_val(s->r, lo1); val = argB + cval; set_reg_val(s->r, lo1, val); s->cc = compute_cc(A_ADD, cval, argB); s->pc = ftpc; break; default: if (error_file) fprintf(error_file, "PC = 0x%llx, Invalid instruction %.2x\n", s->pc, byte0); return STAT_INS; } return STAT_AOK; }

sim/misc/yas.c

/* Assembler for Y86-64 instruction set */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "yas.h" #include "isa.h" void add_symbol(char *, int); int find_symbol(char *); int instr_size(char *); int gui_mode = 0; FILE *outfile; int verbose = 0; /* Generate initialized memory for Verilog? */ int vcode = 0; /* Should it generate code for banked memory? */ int block_factor = 0; int lineno = 1; /* Line number of input file */ int bytepos = 0; /* Address of current instruction being processed */ int error_mode = 0; /* Am I trying to finish off a line with an error? */ int hit_error = 0; /* Have I hit any errors? */ int pass = 1; /* Am I in pass 1 or 2? */ /* General strategy is to read tokens for a complete line and then process them. */ #define TOK_PER_LINE 12 /* Token types */ typedef enum{ TOK_IDENT, TOK_NUM, TOK_REG, TOK_INSTR, TOK_PUNCT, TOK_ERR } token_t; /* Token representation */ typedef struct { char *sval; /* String */ word_t ival; /* Integer */ char cval; /* Character */ token_t type; /* Type */ } token_rec, *token_ptr; /* Information about current input line */ token_rec tokens[TOK_PER_LINE]; int lineno; /* What line number am I processing? */ int bytepos; /* What byte address is the current instruction */ int tcount; /* How many tokens are there in this line? */ int tpos; /* What token am I currently processing */ /* Storage for strings in current line */ #define STRMAX 4096 char strbuf[STRMAX]; int strpos; /* Storage of current line */ char input_line[STRMAX]; void save_line(char *s) { int len = strlen(s); int i; if (len >= STRMAX) fail("Input Line too long"); strcpy(input_line, s); for (i = len-1; input_line[i] == '\n' || input_line[i] == '\r'; i--) input_line[i] = '\0'; /* Remove terminator */ } /* Information about current instruction being generated */ char code[10]; /* Byte encoding */ int codepos = 0; /* Current position in byte encoding */ int bcount = 0; /* Length of current instruction */ /* Debugging information */ char token_type_names[] = {'I', 'N', 'R', 'X', 'P'}; void print_token(FILE *out, token_ptr t) { fprintf(out, " [%c ", token_type_names[t->type]); switch(t->type) { case TOK_IDENT: case TOK_REG: case TOK_INSTR: fprintf(out, "%s]", t->sval); break; case TOK_NUM: fprintf(out, "%lld]", t->ival); break; case TOK_PUNCT: fprintf(out, "%c]", t->cval); break; case TOK_ERR: fprintf(out, "ERR]"); break; default: fprintf(out, "?]"); fail("Unknown token type"); } } /* For debugging */ void print_instruction(FILE *out) { int i; fprintf(out, "Line %d, Byte %d: ", lineno, bytepos); for (i = 0; i < tcount; i++) print_token(out, &tokens[i]); fprintf(out, " Code: "); for (i = 0; i < bcount; i++) fprintf(out, "%.2x ", code[i] & 0xFF); fprintf(out, "\n"); } /* Write len least significant hex digits of value at dest. Don't null terminate */ static void hexstuff(char *dest, word_t value, int len) { int i; for (i = 0; i < len; i++) { char c; int h = (value >> 4*i) & 0xF; c = h < 10 ? h + '0' : h - 10 + 'a'; dest[len-i-1] = c; } } void print_code(FILE *out, int pos) { char outstring[33]; if (pos > 0xFFF) { /* Printing format: 0xHHHH: cccccccccccccccccccc | <line> where HHHH is address cccccccccccccccccccc is code */ if (tcount) { int i; if (pos > 0xFFFF) { fail("Code address limit exceeded"); exit(1); } strcpy(outstring, "0x0000: | "); hexstuff(outstring+2, pos, 4); for (i = 0; i < bcount; i++) hexstuff(outstring+7+2*i, code[i]&0xFF, 2); } else strcpy(outstring, " | "); } else { /* Printing format: 0xHHH: cccccccccccccccccccc | <line> where HHH is address cccccccccccccccccccc is code */ if (tcount) { int i; if (pos > 0xFFF) { fail("Code address limit exceeded"); exit(1); } strcpy(outstring, "0x000: | "); hexstuff(outstring+2, pos, 3); for (i = 0; i < bcount; i++) hexstuff(outstring+7+2*i, code[i]&0xFF, 2); } else strcpy(outstring, " | "); } if (vcode) { fprintf(out, "//%s%s\n", outstring, input_line); if (tcount) { int i; for (i = 0; tcount && i < bcount; i++) { if (block_factor) { fprintf(out, " bank%d[%d] = 8\'h%.2x;\n", (pos+i)%block_factor, (pos+i)/block_factor, code[i] & 0xFF); } else { fprintf(out, " mem[%d] = 8\'h%.2x;\n", pos+i, code[i] & 0xFF); } } } } else { fprintf(out, "%s%s\n", outstring, input_line); } } void fail(char *message) { if (!error_mode) { fprintf(stderr, "Error on line %d: %s\n", lineno, message); fprintf(stderr, "Line %d, Byte 0x%.4x: %s\n", lineno, bytepos, input_line); } error_mode = 1; hit_error = 1; } /* Parse Register from set of tokens and put into high or low 4 bits of code[codepos] */ void get_reg(int codepos, int hi) { int rval = REG_NONE; char c; if (tokens[tpos].type != TOK_REG) { fail("Expecting Register ID"); return; } else { rval = find_register(tokens[tpos].sval); } /* Insert into output */ c = code[codepos]; if (hi) c = (c & 0x0F) | (rval << 4); else c = (c & 0xF0) | rval; code[codepos] = c; tpos++; } /* Get numeric value of given number of bytes */ /* Offset indicates value to subtract from number (for PC relative) */ void get_num(int codepos, int bytes, int offset) { word_t val = 0; int i; if (tokens[tpos].type == TOK_NUM) { val = tokens[tpos].ival; } else if (tokens[tpos].type == TOK_IDENT) { val = find_symbol(tokens[tpos].sval); } else { fail("Number Expected"); return; } val -= offset; for (i = 0; i < bytes; i++) code[codepos+i] = (val >> (i * 8)) & 0xFF; tpos++; } /* Get memory reference. Can be of form: Num(Reg) (Reg) Num Ident Ident(Reg) Put Reg in low position of current byte, and Number in following bytes */ void get_mem(int codepos) { char rval = REG_NONE; word_t val = 0; int i; char c; token_t type = tokens[tpos].type; /* Deal with optional displacement */ if (type == TOK_NUM) { val = tokens[tpos++].ival; type = tokens[tpos].type; } else if (type == TOK_IDENT) { val = find_symbol(tokens[tpos++].sval); type = tokens[tpos].type; } /* Check for optional register */ if (type == TOK_PUNCT) { if (tokens[tpos].cval == '(') { tpos++; if (tokens[tpos].type == TOK_REG) rval = find_register(tokens[tpos++].sval); else { fail("Expecting Register Id"); return; } if (tokens[tpos].type != TOK_PUNCT || tokens[tpos++].cval != ')') { fail("Expecting ')'"); return; } } } c = (code[codepos] & 0xF0) | (rval & 0xF); code[codepos++] = c; for (i = 0; i < 8; i++) code[codepos+i] = (val >> (i*8)) & 0xFF; } void start_line() { int t; error_mode = 0; tpos = 0; tcount = 0; bcount = 0; strpos = 0; for (t = 0; t < TOK_PER_LINE; t++) tokens[t].type = TOK_ERR; } void finish_line() { int size; instr_ptr instr; int savebytepos = bytepos; tpos = 0; codepos = 0; if (tcount == 0) { if (pass > 1) print_code(outfile, savebytepos); start_line(); return; /* Empty line */ } /* Completion of an erroneous line */ if (error_mode) { start_line(); return; } /* See if this is a labeled line */ if (tokens[0].type == TOK_IDENT) { if (tokens[1].type != TOK_PUNCT || tokens[1].cval != ':') { fail("Missing Colon"); start_line(); return; } else { if (pass == 1) add_symbol(tokens[0].sval, bytepos); tpos+=2; if (tcount == 2) { /* That's all for this line */ if (pass > 1) print_code(outfile, savebytepos); start_line(); return; } } } /* Get instruction */ if (tokens[tpos].type != TOK_INSTR) { fail("Bad Instruction"); start_line(); return; } /* Process .pos */ if (strcmp(tokens[tpos].sval, ".pos") == 0) { if (tokens[++tpos].type != TOK_NUM) { fail("Invalid Address"); start_line(); return; } bytepos = tokens[tpos].ival; if (pass > 1) { print_code(outfile, bytepos); } start_line(); return; } /* Process .align */ if (strcmp(tokens[tpos].sval, ".align") == 0) { int a; if (tokens[++tpos].type != TOK_NUM || (a=tokens[tpos].ival) <= 0) { fail("Invalid Alignment"); start_line(); return; } bytepos = ((bytepos+a-1)/a)*a; if (pass > 1) { print_code(outfile, bytepos); } start_line(); return; } /* Get instruction size */ instr = find_instr(tokens[tpos++].sval); if (instr == NULL) { fail("Invalid Instruction"); instr = bad_instr(); } size = instr->bytes; bytepos += size; bcount = size; /* If this is pass 1, then we're done */ if (pass == 1) { start_line(); return; } /* Here's where we really process the instructions */ code[0] = instr->code; code[1] = HPACK(REG_NONE, REG_NONE); switch(instr->arg1) { case R_ARG: get_reg(instr->arg1pos, instr->arg1hi); break; case M_ARG: get_mem(instr->arg1pos); break; case I_ARG: get_num(instr->arg1pos, instr->arg1hi, 0); break; case NO_ARG: default: break; } if (instr->arg2 != NO_ARG) { /* Get comma */ if (tokens[tpos].type != TOK_PUNCT || tokens[tpos].cval != ',') { fail("Expecting Comma"); start_line(); return; } tpos++; /* Get second argument */ switch(instr->arg2) { case R_ARG: get_reg(instr->arg2pos, instr->arg2hi); break; case M_ARG: get_mem(instr->arg2pos); break; case I_ARG: get_num(instr->arg2pos, instr->arg2hi, 0); break; case NO_ARG: default: break; } } print_code(outfile, savebytepos); start_line(); } void add_token(token_t type, char *s, word_t i, char c) { char *t = NULL; if (!tcount) start_line(); if (tpos >= TOK_PER_LINE-1) { fail("Line too long"); return; } if (s) { int len = strlen(s)+1; if (strpos + len > STRMAX) { fail("Line too long"); return; } t = strcpy(strbuf+strpos, s); strpos+= len; } tokens[tcount].type = type; tokens[tcount].sval = t; tokens[tcount].ival = i; tokens[tcount].cval = c; tcount++; } void add_ident(char *s) { add_token(TOK_IDENT, s, 0, ' '); } void add_instr(char *s) { add_token(TOK_INSTR, s, 0, ' '); } void add_reg(char *s) { add_token(TOK_REG, s, 0, ' '); } void add_num(long long i) { add_token(TOK_NUM, NULL, i, ' '); } void add_punct(char c) { add_token(TOK_PUNCT, NULL, 0, c); } #define STAB 1000 #define INIT_CNT 0 int symbol_cnt = INIT_CNT; struct { char *name; int pos; } symbol_table[STAB]; void add_symbol(char *name, int p) { char *t = (char *) malloc(strlen(name)+1); strcpy(t, name); symbol_table[symbol_cnt].name = t; symbol_table[symbol_cnt].pos = p; symbol_cnt++; } int find_symbol(char *name) { int i; for (i = 0; i < symbol_cnt; i++) if (strcmp(name, symbol_table[i].name) == 0) return symbol_table[i].pos; fail("Can't find label"); return -1; } int yywrap() { int i; if (tcount > 0) { fail("Missing end-of-line on final line\n"); } if (verbose && pass > 1) { printf("Symbol Table:\n"); for (i = INIT_CNT; i < symbol_cnt; i++) printf(" %s\t0x%x\n", symbol_table[i].name, symbol_table[i].pos); } return 1; } extern FILE *yyin; int yylex(); static void usage(char *pname) { printf("Usage: %s [-V[n]] file.ys\n", pname); printf(" -V[n] Generate memory initialization in Verilog format (n-way blocking)\n"); exit(0); } int main(int argc, char *argv[]) { int rootlen; char infname[512]; char outfname[512]; int nextarg = 1; if (argc < 2) usage(argv[0]); if (argv[nextarg][0] == '-') { char flag = argv[nextarg][1]; switch (flag) { case 'V': vcode = 1; if (argv[nextarg][2]) { block_factor = atoi(argv[nextarg]+2); if (block_factor != 8) { fprintf(stderr, "Unknown blocking factor %d\n", block_factor); exit(1); } } nextarg++; break; default: usage(argv[0]); } } rootlen = strlen(argv[nextarg])-3; if (strcmp(argv[nextarg]+rootlen, ".ys")) usage(argv[0]); if (rootlen > 500) { fprintf(stderr, "File name too long\n"); exit(1); } strncpy(infname, argv[nextarg], rootlen); strcpy(infname+rootlen, ".ys"); yyin = fopen(infname, "r"); if (!yyin) { fprintf(stderr, "Can't open input file '%s'\n", infname); exit(1); } if (vcode) { outfile = stdout; } else { strncpy(outfname, argv[nextarg], rootlen); strcpy(outfname+rootlen, ".yo"); outfile = fopen(outfname, "w"); if (!outfile) { fprintf(stderr, "Can't open output file '%s'\n", outfname); exit(1); } } pass = 1; yylex(); fclose(yyin); if (hit_error) exit(1); pass = 2; lineno = 1; error_mode = 0; bytepos = 0; yyin = fopen(infname, "r"); if (!yyin) { fprintf(stderr, "Can't open input file '%s'\n", infname); exit(1); } yylex(); fclose(yyin); fclose(outfile); return hit_error; } unsigned long long atollh(const char *p) { return strtoull(p, (char **) NULL, 16); }

sim/misc/yas.h

void save_line(char *); void finish_line(); void add_reg(char *); void add_ident(char *); void add_instr(char *); void add_punct(char); void add_num(long long); void fail(char *msg); unsigned long long atollh(const char *); /* Current line number */ int lineno;

sim/misc/yis.c

/* Instruction set simulator for Y86-64 Architecture */ #include <stdio.h> #include <stdlib.h> #include "isa.h" /* YIS never runs in GUI mode */ int gui_mode = 0; void usage(char *pname) { printf("Usage: %s code_file [max_steps]\n", pname); exit(0); } int main(int argc, char *argv[]) { FILE *code_file; int max_steps = 10000; state_ptr s = new_state(MEM_SIZE); mem_t saver = copy_reg(s->r); mem_t savem; int step = 0; stat_t e = STAT_AOK; if (argc < 2 || argc > 3) usage(argv[0]); code_file = fopen(argv[1], "r"); if (!code_file) { fprintf(stderr, "Can't open code file '%s'\n", argv[1]); exit(1); } if (!load_mem(s->m, code_file, 1)) { printf("Exiting\n"); return 1; } savem = copy_mem(s->m); if (argc > 2) max_steps = atoi(argv[2]); for (step = 0; step < max_steps && e == STAT_AOK; step++) e = step_state(s, stdout); printf("Stopped in %d steps at PC = 0x%llx. Status '%s', CC %s\n", step, s->pc, stat_name(e), cc_name(s->cc)); printf("Changes to registers:\n"); diff_reg(saver, s->r, stdout); printf("\nChanges to memory:\n"); diff_mem(savem, s->m, stdout); free_state(s); free_reg(saver); free_mem(savem); return 0; }

sim/misc/examples.c

/* * Architecture Lab: Part A * * High level specs for the functions that the students will rewrite * in Y86-64 assembly language */ /* $begin examples */ /* linked list element */ typedef struct ELE { long val; struct ELE *next; } *list_ptr; /* sum_list - Sum the elements of a linked list */ long sum_list(list_ptr ls) { long val = 0; while (ls) { val += ls->val; ls = ls->next; } return val; } /* rsum_list - Recursive version of sum_list */ long rsum_list(list_ptr ls) { if (!ls) return 0; else { long val = ls->val; long rest = rsum_list(ls->next); return val + rest; } } /* copy_block - Copy src to dest and return xor checksum of src */ long copy_block(long *src, long *dest, long len) { long result = 0; while (len > 0) { long val = *src++; *dest++ = val; result ^= val; len--; } return result; } /* $end examples */

sim/misc/hcl.lex

%{ #include <stdio.h> #include "node.h" #define YYSTYPE node_ptr #include "hcl.tab.h" extern YYSTYPE yylval; extern int lineno; %} %% [ \r\t\f] ; [\n] lineno++; "#".*\n lineno++ ; quote return(QUOTE); boolsig return(BOOLARG); bool return(BOOL); wordsig return(WORDARG); word return(WORD); in return(IN); '[^']*' yylval = make_quote(yytext); return(QSTRING); [a-zA-Z][a-zA-Z0-9_]* yylval = make_var(yytext); return(VAR); [0-9][0-9]* yylval = make_num(yytext); return(NUM); -[0-9][0-9]* yylval = make_num(yytext); return(NUM); "=" return(ASSIGN); ";" return(SEMI); ":" return(COLON); "," return(COMMA); "(" return(LPAREN); ")" return(RPAREN); "{" return(LBRACE); "}" return(RBRACE); "[" return(LBRACK); "]" return(RBRACK); "&&" return(AND); "||" return(OR); "!=" yylval = make_var(yytext); return(COMP); "==" yylval = make_var(yytext); return(COMP); "<" yylval = make_var(yytext); return(COMP); "<=" yylval = make_var(yytext); return(COMP); ">" yylval = make_var(yytext); return(COMP); ">=" yylval = make_var(yytext); return(COMP); "!" return(NOT); %%

sim/misc/hcl.y

%{ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "node.h" #define YYSTYPE node_ptr /* Current line number. Maintained by lex */ int lineno = 1; #define ERRLIM 5 int errcnt = 0; FILE *outfile; int yyparse(void); int yylex(void); void yyerror(const char *str) { fprintf(stderr, "Error, near line %d: %s\n", lineno, str); if (++errcnt > ERRLIM) { fprintf(stderr, "Too many errors, aborting\n"); exit(1); } } static char errmsg[1024]; void yyserror(const char *str, char *other) { sprintf(errmsg, str, other); yyerror(errmsg); } int yywrap() { return 1; } int main(int argc, char **argv) { init_node(argc, argv); outfile = stdout; yyparse(); finish_node(0); return errcnt != 0; } %} %token QUOTE BOOLARG BOOL WORDARG WORD QSTRING VAR NUM ASSIGN SEMI COLON COMMA LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK AND OR NOT COMP IN /* All operators are left associative. Listed from lowest to highest */ %left OR %left AND %left NOT %left COMP %left IN %% statements: /* empty */ | statements statement ; statement: QUOTE QSTRING { insert_code($2); } | BOOLARG VAR QSTRING { add_arg($2, $3, 1); } | WORDARG VAR QSTRING { add_arg($2, $3, 0); } | BOOL VAR ASSIGN expr SEMI { gen_funct($2, $4, 1); } | WORD VAR ASSIGN expr SEMI { gen_funct($2, $4, 0); } ; expr: VAR { $$=$1; } | NUM { $$=$1; } | LPAREN expr RPAREN { $$=$2; } | NOT expr { $$=make_not($2); } | expr AND expr { $$=make_and($1, $3); } | expr OR expr { $$=make_or($1, $3); } | expr COMP expr { $$=make_comp($2,$1,$3); } | expr IN LBRACE exprlist RBRACE { $$=make_ele($1, $4);} | LBRACK caselist RBRACK { $$=$2; } ; exprlist: expr { $$=$1; } | exprlist COMMA expr { $$=concat($1, $3); } caselist: /* Empty */ { $$=NULL; } | caselist expr COLON expr SEMI { $$=concat($1, make_case($2, $4));}

sim/misc/hcl.tab.c

/* A Bison parser, made by GNU Bison 2.7. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.7" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Copy the first part of user declarations. */ /* Line 371 of yacc.c */ #line 1 "hcl.y" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "node.h" #define YYSTYPE node_ptr /* Current line number. Maintained by lex */ int lineno = 1; #define ERRLIM 5 int errcnt = 0; FILE *outfile; int yyparse(void); int yylex(void); void yyerror(const char *str) { fprintf(stderr, "Error, near line %d: %s\n", lineno, str); if (++errcnt > ERRLIM) { fprintf(stderr, "Too many errors, aborting\n"); exit(1); } } static char errmsg[1024]; void yyserror(const char *str, char *other) { sprintf(errmsg, str, other); yyerror(errmsg); } int yywrap() { return 1; } int main(int argc, char **argv) { init_node(argc, argv); outfile = stdout; yyparse(); finish_node(0); return errcnt != 0; } /* Line 371 of yacc.c */ #line 119 "hcl.tab.c" # ifndef YY_NULL # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULL nullptr # else # define YY_NULL 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* In a future release of Bison, this section will be replaced by #include "hcl.tab.h". */ #ifndef YY_YY_HCL_TAB_H_INCLUDED # define YY_YY_HCL_TAB_H_INCLUDED /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { QUOTE = 258, BOOLARG = 259, BOOL = 260, WORDARG = 261, WORD = 262, QSTRING = 263, VAR = 264, NUM = 265, ASSIGN = 266, SEMI = 267, COLON = 268, COMMA = 269, LPAREN = 270, RPAREN = 271, LBRACE = 272, RBRACE = 273, LBRACK = 274, RBRACK = 275, AND = 276, OR = 277, NOT = 278, COMP = 279, IN = 280 }; #endif #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef int YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ #endif /* !YY_YY_HCL_TAB_H_INCLUDED */ /* Copy the second part of user declarations. */ /* Line 390 of yacc.c */ #line 210 "hcl.tab.c" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include <stddef.h> /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include <libintl.h> /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(N) (N) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include <alloca.h> /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include <malloc.h> /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (YYID (0)) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 78 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 26 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 6 /* YYNRULES -- Number of rules. */ #define YYNRULES 21 /* YYNRULES -- Number of states. */ #define YYNSTATES 49 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 280 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint8 yyprhs[] = { 0, 0, 3, 4, 7, 10, 14, 18, 24, 30, 32, 34, 38, 41, 45, 49, 53, 59, 63, 65, 69, 70 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { 27, 0, -1, -1, 27, 28, -1, 3, 8, -1, 4, 9, 8, -1, 6, 9, 8, -1, 5, 9, 11, 29, 12, -1, 7, 9, 11, 29, 12, -1, 9, -1, 10, -1, 15, 29, 16, -1, 23, 29, -1, 29, 21, 29, -1, 29, 22, 29, -1, 29, 24, 29, -1, 29, 25, 17, 30, 18, -1, 19, 31, 20, -1, 29, -1, 30, 14, 29, -1, -1, 31, 29, 13, 29, 12, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { 0, 65, 65, 66, 70, 71, 72, 73, 74, 78, 79, 80, 81, 82, 83, 84, 85, 86, 90, 91, 94, 95 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "QUOTE", "BOOLARG", "BOOL", "WORDARG", "WORD", "QSTRING", "VAR", "NUM", "ASSIGN", "SEMI", "COLON", "COMMA", "LPAREN", "RPAREN", "LBRACE", "RBRACE", "LBRACK", "RBRACK", "AND", "OR", "NOT", "COMP", "IN", "$accept", "statements", "statement", "expr", "exprlist", "caselist", YY_NULL }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 26, 27, 27, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 31, 31 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 0, 2, 2, 3, 3, 5, 5, 1, 1, 3, 2, 3, 3, 3, 5, 3, 1, 3, 0, 5 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. Performed when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 2, 0, 1, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 5, 0, 6, 0, 9, 10, 0, 20, 0, 0, 0, 0, 0, 12, 7, 0, 0, 0, 0, 8, 11, 17, 0, 13, 14, 15, 0, 0, 18, 0, 0, 0, 16, 21, 19 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { -1, 1, 8, 23, 43, 26 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -18 static const yytype_int8 yypact[] = { -18, 66, -18, -7, -3, 8, 18, 23, -18, -18, -4, 22, 26, 32, -18, 21, -18, 21, -18, -18, 21, -18, 21, 25, 30, -14, 6, -5, -18, 21, 21, 21, 24, -18, -18, -18, 43, -5, 14, 20, 21, 21, 53, 4, 36, 21, -18, -18, 53 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -18, -18, -18, -17, -18, -18 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { 24, 9, 34, 25, 14, 27, 10, 29, 30, 36, 31, 32, 37, 38, 39, 18, 19, 11, 45, 31, 32, 20, 46, 42, 44, 21, 35, 12, 48, 22, 18, 19, 13, 15, 16, 29, 20, 28, 31, 32, 21, 40, 33, 17, 22, 32, 29, 30, 47, 31, 32, 29, 30, 0, 31, 32, 41, 29, 30, 0, 31, 32, 0, 0, 29, 30, 2, 31, 32, 3, 4, 5, 6, 7, 29, 30, 0, 31, 32 }; #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-18))) #define yytable_value_is_error(Yytable_value) \ YYID (0) static const yytype_int8 yycheck[] = { 17, 8, 16, 20, 8, 22, 9, 21, 22, 26, 24, 25, 29, 30, 31, 9, 10, 9, 14, 24, 25, 15, 18, 40, 41, 19, 20, 9, 45, 23, 9, 10, 9, 11, 8, 21, 15, 12, 24, 25, 19, 17, 12, 11, 23, 25, 21, 22, 12, 24, 25, 21, 22, -1, 24, 25, 13, 21, 22, -1, 24, 25, -1, -1, 21, 22, 0, 24, 25, 3, 4, 5, 6, 7, 21, 22, -1, 24, 25 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 27, 0, 3, 4, 5, 6, 7, 28, 8, 9, 9, 9, 9, 8, 11, 8, 11, 9, 10, 15, 19, 23, 29, 29, 29, 31, 29, 12, 21, 22, 24, 25, 12, 16, 20, 29, 29, 29, 29, 17, 13, 29, 30, 29, 14, 18, 12, 29 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. However, YYFAIL appears to be in use. Nevertheless, it is formally deprecated in Bison 2.4.2's NEWS entry, where a plan to phase it out is discussed. */ #define YYFAIL goto yyerrlab #if defined YYFAIL /* This is here to suppress warnings from the GCC cpp's -Wunused-macros. Normally we don't worry about that warning, but some users do, and we want to make it easy for users to remove YYFAIL uses, which will produce warnings from Bison 2.5. */ #endif #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include <stdio.h> /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { FILE *yyo = yyoutput; YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULL; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - Assume YYFAIL is not used. It's too flawed to consider. See <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html> for details. YYERROR is fine as it does not invoke this function. - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* The lookahead symbol. */ int yychar; #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif /* The semantic value of the lookahead symbol. */ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 4: /* Line 1792 of yacc.c */ #line 70 "hcl.y" { insert_code((yyvsp[(2) - (2)])); } break; case 5: /* Line 1792 of yacc.c */ #line 71 "hcl.y" { add_arg((yyvsp[(2) - (3)]), (yyvsp[(3) - (3)]), 1); } break; case 6: /* Line 1792 of yacc.c */ #line 72 "hcl.y" { add_arg((yyvsp[(2) - (3)]), (yyvsp[(3) - (3)]), 0); } break; case 7: /* Line 1792 of yacc.c */ #line 73 "hcl.y" { gen_funct((yyvsp[(2) - (5)]), (yyvsp[(4) - (5)]), 1); } break; case 8: /* Line 1792 of yacc.c */ #line 74 "hcl.y" { gen_funct((yyvsp[(2) - (5)]), (yyvsp[(4) - (5)]), 0); } break; case 9: /* Line 1792 of yacc.c */ #line 78 "hcl.y" { (yyval)=(yyvsp[(1) - (1)]); } break; case 10: /* Line 1792 of yacc.c */ #line 79 "hcl.y" { (yyval)=(yyvsp[(1) - (1)]); } break; case 11: /* Line 1792 of yacc.c */ #line 80 "hcl.y" { (yyval)=(yyvsp[(2) - (3)]); } break; case 12: /* Line 1792 of yacc.c */ #line 81 "hcl.y" { (yyval)=make_not((yyvsp[(2) - (2)])); } break; case 13: /* Line 1792 of yacc.c */ #line 82 "hcl.y" { (yyval)=make_and((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])); } break; case 14: /* Line 1792 of yacc.c */ #line 83 "hcl.y" { (yyval)=make_or((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])); } break; case 15: /* Line 1792 of yacc.c */ #line 84 "hcl.y" { (yyval)=make_comp((yyvsp[(2) - (3)]),(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); } break; case 16: /* Line 1792 of yacc.c */ #line 85 "hcl.y" { (yyval)=make_ele((yyvsp[(1) - (5)]), (yyvsp[(4) - (5)]));} break; case 17: /* Line 1792 of yacc.c */ #line 86 "hcl.y" { (yyval)=(yyvsp[(2) - (3)]); } break; case 18: /* Line 1792 of yacc.c */ #line 90 "hcl.y" { (yyval)=(yyvsp[(1) - (1)]); } break; case 19: /* Line 1792 of yacc.c */ #line 91 "hcl.y" { (yyval)=concat((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])); } break; case 20: /* Line 1792 of yacc.c */ #line 94 "hcl.y" { (yyval)=NULL; } break; case 21: /* Line 1792 of yacc.c */ #line 95 "hcl.y" { (yyval)=concat((yyvsp[(1) - (5)]), make_case((yyvsp[(2) - (5)]), (yyvsp[(4) - (5)])));} break; /* Line 1792 of yacc.c */ #line 1542 "hcl.tab.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); }

sim/misc/hcl.tab.h

/* A Bison parser, made by GNU Bison 2.7. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_YY_HCL_TAB_H_INCLUDED # define YY_YY_HCL_TAB_H_INCLUDED /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { QUOTE = 258, BOOLARG = 259, BOOL = 260, WORDARG = 261, WORD = 262, QSTRING = 263, VAR = 264, NUM = 265, ASSIGN = 266, SEMI = 267, COLON = 268, COMMA = 269, LPAREN = 270, RPAREN = 271, LBRACE = 272, RBRACE = 273, LBRACK = 274, RBRACK = 275, AND = 276, OR = 277, NOT = 278, COMP = 279, IN = 280 }; #endif #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef int YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ #endif /* !YY_YY_HCL_TAB_H_INCLUDED */

sim/misc/yas-grammar.lex

/* Grammar for Y86-64 Assembler */ #include "yas.h" Instr rrmovq|cmovle|cmovl|cmove|cmovne|cmovge|cmovg|rmmovq|mrmovq|irmovq|addq|subq|andq|xorq|jmp|jle|jl|je|jne|jge|jg|call|ret|pushq|popq|"."byte|"."word|"."long|"."quad|"."pos|"."align|halt|nop|iaddq Letter [a-zA-Z] Digit [0-9] Ident {Letter}({Letter}|{Digit}|_)* Hex [0-9a-fA-F] Blank [ \t] Newline [\n\r] Return [\r] Char [^\n\r] Reg %rax|%rcx|%rdx|%rbx|%rsi|%rdi|%rsp|%rbp|%r8|%r9|%r10|%r11|%r12|%r13|%r14 %x ERR COM %% ^{Char}*{Return}*{Newline} { save_line(yytext); REJECT;} /* Snarf input line */ #{Char}*{Return}*{Newline} {finish_line(); lineno++;} "//"{Char}*{Return}*{Newline} {finish_line(); lineno++;} "/*"{Char}*{Return}*{Newline} {finish_line(); lineno++;} {Blank}*{Return}*{Newline} {finish_line(); lineno++;} {Blank}+ ; "$"+ ; {Instr} add_instr(yytext); {Reg} add_reg(yytext); [-]?{Digit}+ add_num(atoll(yytext)); "0"[xX]{Hex}+ add_num(atollh(yytext)); [():,] add_punct(*yytext); {Ident} add_ident(yytext); {Char} {; BEGIN ERR;} <ERR>{Char}*{Newline} {fail("Invalid line"); lineno++; BEGIN 0;} %% unsigned int atoh(const char *s) { return(strtoul(s, NULL, 16)); }

sim/misc/lex.yy.c

#line 3 "lex.yy.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 37 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include <inttypes.h> typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern yy_size_t yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ yy_size_t yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 33 #define YY_END_OF_BUFFER 34 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[63] = { 0, 0, 0, 34, 33, 1, 2, 32, 33, 33, 33, 18, 19, 17, 33, 12, 16, 15, 28, 14, 30, 11, 22, 23, 11, 11, 11, 11, 20, 33, 21, 26, 0, 3, 24, 0, 10, 13, 12, 29, 27, 31, 11, 11, 9, 11, 11, 25, 13, 11, 11, 11, 6, 11, 8, 11, 4, 11, 11, 11, 5, 7, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 1, 5, 1, 1, 6, 7, 8, 9, 1, 1, 10, 11, 1, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 14, 15, 16, 17, 1, 1, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 1, 20, 1, 21, 1, 18, 22, 18, 23, 24, 18, 25, 18, 26, 18, 18, 27, 18, 28, 29, 18, 30, 31, 32, 33, 34, 18, 35, 18, 18, 18, 36, 37, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[39] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1 } ; static yyconst flex_int16_t yy_base[66] = { 0, 0, 0, 76, 77, 77, 77, 59, 71, 67, 65, 77, 77, 77, 59, 58, 77, 77, 53, 52, 51, 0, 77, 77, 37, 37, 30, 34, 77, 25, 77, 77, 58, 77, 77, 53, 77, 47, 46, 77, 77, 77, 0, 28, 0, 27, 24, 77, 42, 26, 19, 28, 18, 25, 16, 21, 0, 20, 20, 19, 0, 0, 77, 38, 40, 41 } ; static yyconst flex_int16_t yy_def[66] = { 0, 62, 1, 62, 62, 62, 62, 62, 63, 62, 64, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 65, 62, 62, 65, 65, 65, 65, 62, 62, 62, 62, 63, 62, 62, 64, 62, 62, 62, 62, 62, 62, 65, 65, 65, 65, 65, 62, 62, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, 62, 62, 62 } ; static yyconst flex_int16_t yy_nxt[116] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 4, 24, 21, 21, 21, 25, 21, 21, 21, 26, 21, 21, 21, 21, 27, 28, 29, 30, 32, 32, 35, 35, 42, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 48, 51, 50, 49, 38, 48, 36, 33, 47, 46, 45, 44, 43, 41, 40, 39, 38, 37, 36, 34, 33, 31, 62, 3, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62 } ; static yyconst flex_int16_t yy_chk[116] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 63, 63, 64, 64, 65, 59, 58, 57, 55, 54, 53, 52, 51, 50, 49, 48, 46, 45, 43, 38, 37, 35, 32, 29, 27, 26, 25, 24, 20, 19, 18, 15, 14, 10, 9, 8, 7, 3, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "hcl.lex" #line 2 "hcl.lex" #include <stdio.h> #include "node.h" #define YYSTYPE node_ptr #include "hcl.tab.h" extern YYSTYPE yylval; extern int lineno; #line 504 "lex.yy.c" #define INITIAL 0 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include <unistd.h> #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (void ); int yyget_debug (void ); void yyset_debug (int debug_flag ); YY_EXTRA_TYPE yyget_extra (void ); void yyset_extra (YY_EXTRA_TYPE user_defined ); FILE *yyget_in (void ); void yyset_in (FILE * in_str ); FILE *yyget_out (void ); void yyset_out (FILE * out_str ); yy_size_t yyget_leng (void ); char *yyget_text (void ); int yyget_lineno (void ); void yyset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif static void yyunput (int c,char *buf_ptr ); #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 11 "hcl.lex" #line 688 "lex.yy.c" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 63 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 77 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 12 "hcl.lex" ; YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP #line 13 "hcl.lex" lineno++; YY_BREAK case 3: /* rule 3 can match eol */ YY_RULE_SETUP #line 14 "hcl.lex" lineno++ ; YY_BREAK case 4: YY_RULE_SETUP #line 15 "hcl.lex" return(QUOTE); YY_BREAK case 5: YY_RULE_SETUP #line 16 "hcl.lex" return(BOOLARG); YY_BREAK case 6: YY_RULE_SETUP #line 17 "hcl.lex" return(BOOL); YY_BREAK case 7: YY_RULE_SETUP #line 18 "hcl.lex" return(WORDARG); YY_BREAK case 8: YY_RULE_SETUP #line 19 "hcl.lex" return(WORD); YY_BREAK case 9: YY_RULE_SETUP #line 20 "hcl.lex" return(IN); YY_BREAK case 10: /* rule 10 can match eol */ YY_RULE_SETUP #line 21 "hcl.lex" yylval = make_quote(yytext); return(QSTRING); YY_BREAK case 11: YY_RULE_SETUP #line 22 "hcl.lex" yylval = make_var(yytext); return(VAR); YY_BREAK case 12: YY_RULE_SETUP #line 23 "hcl.lex" yylval = make_num(yytext); return(NUM); YY_BREAK case 13: YY_RULE_SETUP #line 24 "hcl.lex" yylval = make_num(yytext); return(NUM); YY_BREAK case 14: YY_RULE_SETUP #line 25 "hcl.lex" return(ASSIGN); YY_BREAK case 15: YY_RULE_SETUP #line 26 "hcl.lex" return(SEMI); YY_BREAK case 16: YY_RULE_SETUP #line 27 "hcl.lex" return(COLON); YY_BREAK case 17: YY_RULE_SETUP #line 28 "hcl.lex" return(COMMA); YY_BREAK case 18: YY_RULE_SETUP #line 29 "hcl.lex" return(LPAREN); YY_BREAK case 19: YY_RULE_SETUP #line 30 "hcl.lex" return(RPAREN); YY_BREAK case 20: YY_RULE_SETUP #line 31 "hcl.lex" return(LBRACE); YY_BREAK case 21: YY_RULE_SETUP #line 32 "hcl.lex" return(RBRACE); YY_BREAK case 22: YY_RULE_SETUP #line 33 "hcl.lex" return(LBRACK); YY_BREAK case 23: YY_RULE_SETUP #line 34 "hcl.lex" return(RBRACK); YY_BREAK case 24: YY_RULE_SETUP #line 35 "hcl.lex" return(AND); YY_BREAK case 25: YY_RULE_SETUP #line 36 "hcl.lex" return(OR); YY_BREAK case 26: YY_RULE_SETUP #line 37 "hcl.lex" yylval = make_var(yytext); return(COMP); YY_BREAK case 27: YY_RULE_SETUP #line 38 "hcl.lex" yylval = make_var(yytext); return(COMP); YY_BREAK case 28: YY_RULE_SETUP #line 39 "hcl.lex" yylval = make_var(yytext); return(COMP); YY_BREAK case 29: YY_RULE_SETUP #line 40 "hcl.lex" yylval = make_var(yytext); return(COMP); YY_BREAK case 30: YY_RULE_SETUP #line 41 "hcl.lex" yylval = make_var(yytext); return(COMP); YY_BREAK case 31: YY_RULE_SETUP #line 42 "hcl.lex" yylval = make_var(yytext); return(COMP); YY_BREAK case 32: YY_RULE_SETUP #line 43 "hcl.lex" return(NOT); YY_BREAK case 33: YY_RULE_SETUP #line 44 "hcl.lex" ECHO; YY_BREAK #line 939 "lex.yy.c" case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 63 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 63 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 62); return yy_is_jam ? 0 : yy_current_state; } static void yyunput (int c, register char * yy_bp ) { register char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register yy_size_t number_to_move = (yy_n_chars) + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { return yy_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ yy_size_t yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param line_number * */ void yyset_lineno (int line_number ) { yylineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str ) { yyin = in_str ; } void yyset_out (FILE * out_str ) { yyout = out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int bdebug ) { yy_flex_debug = bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 44 "hcl.lex"

sim/misc/yas-grammar.c

#line 3 "lex.yy.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 37 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include <inttypes.h> typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern yy_size_t yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ yy_size_t yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 16 #define YY_END_OF_BUFFER 17 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_acclist[291] = { 0, 17, 14, 16, 6, 14, 16, 5, 16, 5, 16, 14, 16, 7, 14, 16, 14, 16, 12, 14, 16, 14, 16, 14, 16, 14, 16, 10, 14, 16, 10, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 14, 16, 6, 14, 16, 1, 5, 16, 1, 5, 16, 14, 16, 7, 14, 16, 14, 16, 12, 14, 16, 14, 16, 14, 16, 14, 16, 10, 14, 16, 10, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, 16, 15, 16, 16, 6, 5, 5, 2, 2, 7, 10, 13, 13, 13, 13, 13, 13, 13, 13, 8, 13, 8, 13, 8, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 6, 1, 5, 1, 5, 1, 2, 1, 2, 7, 10, 13, 13, 13, 13, 13, 13, 13, 13, 8, 13, 8, 13, 8, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 9, 4, 4, 3, 3, 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 9, 1, 4, 1, 4, 1, 3, 1, 3, 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 8, 13, 13, 13, 13, 13, 13, 13, 8, 13, 13, 13, 13, 13, 13, 13, 8, 13, 8, 13, 13, 13, 13, 13, 13, 8, 13, 8, 13, 13, 13, 13, 13, 13 } ; static yyconst flex_int16_t yy_accept[258] = { 0, 1, 1, 1, 1, 1, 1, 1, 2, 4, 7, 9, 11, 13, 16, 18, 21, 23, 25, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 71, 74, 77, 80, 82, 85, 87, 90, 92, 94, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126, 129, 132, 135, 138, 139, 141, 142, 143, 144, 145, 145, 146, 147, 148, 148, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 150, 151, 152, 153, 154, 155, 156, 157, 159, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 179, 181, 181, 183, 185, 186, 186, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 188, 189, 190, 191, 192, 193, 194, 195, 197, 199, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 212, 213, 213, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 215, 216, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 236, 238, 238, 240, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 257, 257, 257, 258, 258, 258, 259, 260, 261, 262, 263, 264, 265, 265, 265, 265, 266, 266, 266, 267, 268, 269, 270, 271, 272, 273, 273, 275, 277, 278, 279, 280, 281, 282, 282, 284, 286, 287, 288, 289, 290, 291, 291 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 5, 6, 7, 1, 1, 8, 8, 9, 1, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, 19, 20, 8, 1, 1, 1, 1, 1, 1, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 22, 22, 1, 1, 1, 1, 24, 1, 25, 26, 27, 28, 29, 21, 30, 31, 32, 33, 22, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[48] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 4, 4, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 } ; static yyconst flex_int16_t yy_base[271] = { 0, 0, 47, 92, 94, 0, 0, 691, 692, 97, 692, 99, 101, 684, 649, 692, 0, 81, 99, 86, 0, 0, 82, 87, 663, 88, 95, 647, 649, 80, 98, 642, 647, 131, 137, 692, 133, 139, 141, 145, 147, 183, 201, 149, 123, 0, 246, 258, 129, 131, 135, 144, 148, 153, 178, 182, 134, 155, 190, 692, 692, 205, 692, 209, 216, 692, 220, 677, 281, 0, 648, 634, 643, 642, 635, 640, 225, 227, 0, 0, 648, 647, 640, 636, 638, 643, 635, 0, 640, 639, 629, 637, 630, 626, 625, 621, 619, 625, 574, 582, 567, 229, 692, 233, 239, 692, 241, 268, 692, 270, 272, 320, 0, 276, 278, 280, 284, 286, 289, 293, 295, 349, 249, 275, 276, 299, 277, 302, 292, 314, 315, 324, 343, 345, 356, 352, 358, 361, 354, 365, 370, 374, 385, 372, 312, 692, 341, 692, 560, 376, 559, 136, 299, 572, 560, 561, 554, 548, 531, 315, 692, 400, 412, 692, 414, 0, 518, 512, 515, 503, 490, 502, 487, 484, 478, 480, 459, 455, 451, 427, 416, 420, 422, 424, 431, 433, 435, 437, 439, 442, 444, 446, 448, 450, 692, 452, 454, 692, 456, 0, 436, 448, 446, 455, 458, 461, 465, 467, 470, 477, 479, 482, 484, 486, 433, 432, 414, 692, 363, 331, 497, 305, 297, 288, 263, 247, 194, 525, 531, 533, 535, 537, 539, 516, 520, 525, 526, 536, 530, 540, 198, 196, 187, 166, 127, 116, 82, 77, 574, 551, 553, 557, 555, 560, 562, 564, 692, 610, 614, 618, 112, 621, 625, 629, 633, 637, 641, 645, 648, 651, 655 } ; static yyconst flex_int16_t yy_def[271] = { 0, 256, 256, 257, 257, 258, 258, 256, 256, 256, 256, 256, 259, 256, 256, 256, 260, 256, 256, 260, 260, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 262, 262, 256, 256, 263, 262, 262, 262, 262, 262, 262, 41, 41, 264, 264, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 265, 256, 256, 256, 256, 256, 259, 256, 256, 256, 256, 260, 256, 256, 256, 256, 256, 256, 266, 267, 268, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 262, 256, 256, 262, 256, 256, 263, 256, 256, 262, 262, 41, 262, 262, 262, 262, 262, 262, 269, 270, 41, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 265, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 266, 256, 256, 267, 256, 256, 268, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, 269, 256, 256, 270, 256, 256, 121, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 256, 256, 256, 256, 256, 256, 261, 261, 261, 261, 261, 261, 261, 262, 262, 262, 262, 262, 262, 47, 47, 47, 47, 47, 47, 47, 256, 261, 261, 261, 261, 261, 261, 261, 262, 47, 47, 47, 47, 47, 47, 47, 0, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256 } ; static yyconst flex_int16_t yy_nxt[740] = { 0, 8, 9, 10, 11, 12, 13, 14, 15, 8, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 8, 22, 21, 23, 21, 21, 21, 24, 25, 26, 21, 27, 28, 21, 29, 21, 30, 31, 21, 21, 21, 21, 32, 21, 33, 34, 35, 36, 37, 38, 39, 40, 33, 41, 42, 43, 44, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 33, 47, 46, 48, 46, 46, 46, 49, 50, 51, 46, 52, 53, 46, 54, 46, 55, 56, 46, 46, 46, 46, 57, 46, 59, 59, 59, 59, 61, 62, 63, 62, 63, 65, 66, 70, 71, 76, 78, 80, 77, 82, 85, 69, 72, 87, 94, 81, 73, 74, 87, 83, 95, 87, 88, 75, 96, 86, 89, 90, 91, 78, 97, 102, 103, 105, 106, 98, 104, 105, 106, 108, 109, 102, 103, 121, 110, 102, 103, 102, 103, 102, 103, 125, 87, 127, 122, 119, 122, 128, 120, 122, 122, 126, 122, 87, 122, 147, 121, 122, 122, 122, 130, 131, 129, 122, 142, 132, 133, 134, 122, 147, 122, 122, 111, 102, 103, 135, 122, 136, 122, 143, 145, 145, 87, 112, 112, 112, 112, 112, 112, 112, 112, 102, 103, 122, 61, 62, 63, 122, 139, 62, 63, 122, 137, 87, 140, 122, 65, 66, 138, 141, 65, 66, 87, 113, 114, 160, 161, 163, 164, 102, 103, 217, 115, 102, 103, 247, 116, 117, 104, 105, 106, 105, 106, 118, 101, 101, 102, 103, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 102, 103, 101, 101, 101, 101, 101, 101, 101, 101, 108, 109, 108, 109, 102, 103, 122, 110, 102, 103, 102, 103, 102, 103, 122, 123, 102, 103, 102, 103, 246, 102, 103, 124, 146, 194, 195, 197, 198, 147, 147, 87, 200, 201, 122, 148, 149, 150, 151, 187, 122, 122, 122, 203, 145, 145, 189, 160, 161, 205, 190, 152, 102, 103, 188, 192, 122, 122, 191, 122, 147, 245, 202, 180, 122, 204, 147, 122, 181, 181, 244, 122, 122, 87, 182, 183, 184, 185, 206, 122, 122, 122, 130, 147, 147, 147, 147, 147, 217, 122, 186, 199, 199, 199, 199, 199, 199, 199, 199, 199, 122, 130, 122, 199, 199, 199, 199, 199, 122, 122, 122, 122, 130, 122, 130, 122, 207, 122, 122, 122, 217, 122, 122, 122, 209, 130, 122, 122, 208, 122, 122, 122, 160, 161, 210, 122, 130, 122, 211, 122, 212, 213, 122, 147, 163, 164, 163, 164, 102, 103, 122, 147, 102, 103, 102, 103, 102, 103, 181, 181, 181, 181, 181, 102, 103, 102, 103, 102, 103, 102, 103, 102, 103, 217, 102, 103, 102, 103, 102, 103, 102, 103, 194, 195, 194, 195, 197, 198, 197, 198, 217, 181, 240, 122, 181, 87, 181, 181, 227, 181, 231, 122, 181, 122, 130, 122, 181, 229, 181, 130, 228, 122, 122, 122, 230, 122, 130, 232, 234, 87, 122, 226, 122, 122, 122, 225, 122, 122, 233, 130, 122, 235, 122, 236, 122, 122, 122, 237, 130, 122, 224, 122, 122, 122, 122, 238, 87, 122, 239, 122, 223, 122, 130, 222, 130, 87, 241, 102, 103, 221, 242, 87, 243, 102, 103, 102, 103, 102, 103, 102, 103, 102, 103, 122, 130, 249, 220, 122, 87, 250, 87, 251, 122, 122, 248, 122, 87, 122, 130, 230, 122, 122, 230, 122, 230, 122, 230, 122, 252, 253, 219, 122, 218, 254, 130, 122, 102, 103, 122, 130, 122, 130, 122, 255, 122, 130, 122, 122, 122, 122, 122, 122, 122, 130, 217, 122, 216, 122, 130, 122, 130, 215, 130, 214, 147, 147, 179, 178, 177, 230, 58, 58, 58, 58, 60, 60, 60, 60, 64, 64, 64, 64, 79, 79, 79, 101, 101, 101, 101, 107, 107, 107, 107, 122, 122, 122, 122, 144, 144, 144, 144, 159, 159, 159, 159, 162, 162, 162, 162, 165, 165, 193, 193, 193, 193, 196, 196, 196, 196, 176, 87, 175, 174, 87, 173, 87, 87, 87, 87, 172, 171, 170, 169, 168, 167, 166, 158, 157, 156, 155, 154, 153, 67, 100, 99, 93, 92, 84, 68, 67, 256, 7, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256 } ; static yyconst flex_int16_t yy_chk[740] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 9, 9, 9, 11, 11, 12, 12, 17, 17, 18, 19, 22, 18, 23, 25, 260, 17, 247, 29, 22, 17, 17, 246, 23, 29, 26, 26, 17, 30, 25, 26, 26, 26, 19, 30, 33, 33, 36, 36, 30, 34, 34, 34, 37, 37, 38, 38, 44, 38, 39, 39, 40, 40, 43, 43, 48, 245, 49, 48, 43, 49, 50, 43, 56, 50, 48, 48, 244, 49, 151, 44, 56, 50, 51, 51, 51, 50, 52, 56, 51, 51, 51, 53, 151, 57, 52, 39, 41, 41, 52, 53, 53, 57, 57, 58, 58, 243, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 54, 61, 61, 61, 55, 55, 63, 63, 54, 54, 242, 55, 55, 64, 64, 54, 55, 66, 66, 241, 42, 42, 76, 76, 77, 77, 101, 101, 240, 42, 103, 103, 226, 42, 42, 104, 104, 104, 106, 106, 42, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 107, 107, 109, 109, 110, 110, 122, 110, 113, 113, 114, 114, 115, 115, 122, 47, 116, 116, 117, 117, 225, 118, 118, 47, 68, 119, 119, 120, 120, 68, 68, 224, 123, 124, 126, 68, 68, 68, 68, 113, 123, 124, 126, 126, 144, 144, 115, 159, 159, 128, 116, 68, 111, 111, 114, 118, 125, 128, 117, 127, 152, 223, 125, 111, 125, 127, 152, 127, 111, 111, 222, 129, 130, 221, 111, 111, 111, 111, 129, 129, 130, 131, 131, 146, 146, 146, 146, 146, 219, 131, 111, 121, 121, 121, 121, 121, 121, 121, 121, 121, 132, 132, 133, 121, 121, 121, 121, 121, 132, 135, 133, 138, 133, 134, 134, 136, 135, 135, 137, 138, 218, 134, 139, 136, 138, 136, 137, 140, 137, 143, 139, 141, 161, 161, 140, 140, 139, 143, 141, 141, 142, 143, 142, 149, 162, 162, 164, 164, 180, 180, 142, 149, 181, 181, 182, 182, 183, 183, 180, 180, 180, 180, 180, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 216, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 195, 195, 196, 196, 198, 198, 215, 183, 214, 200, 185, 179, 186, 182, 187, 183, 191, 200, 186, 202, 200, 201, 184, 189, 185, 202, 188, 202, 203, 201, 190, 204, 201, 192, 205, 178, 203, 177, 206, 204, 207, 176, 205, 208, 203, 204, 206, 206, 207, 207, 209, 208, 210, 209, 208, 211, 175, 212, 209, 213, 210, 210, 174, 211, 211, 212, 173, 213, 212, 172, 213, 220, 220, 227, 227, 171, 220, 170, 220, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 233, 169, 234, 168, 233, 167, 233, 235, 236, 227, 234, 166, 238, 234, 228, 235, 236, 229, 237, 231, 238, 232, 239, 235, 236, 158, 237, 157, 238, 237, 239, 248, 248, 249, 249, 250, 250, 252, 239, 251, 251, 249, 253, 250, 254, 252, 255, 251, 252, 156, 253, 155, 254, 253, 255, 254, 154, 255, 153, 150, 148, 100, 99, 98, 248, 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, 259, 261, 261, 261, 262, 262, 262, 262, 263, 263, 263, 263, 264, 264, 264, 264, 265, 265, 265, 265, 266, 266, 266, 266, 267, 267, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 86, 85, 84, 83, 82, 81, 80, 75, 74, 73, 72, 71, 70, 67, 32, 31, 28, 27, 24, 14, 13, 7, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256 } ; extern int yy_flex_debug; int yy_flex_debug = 0; static yy_state_type *yy_state_buf=0, *yy_state_ptr=0; static char *yy_full_match; static int yy_lp; #define REJECT \ { \ *yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \ yy_cp = (yy_full_match); /* restore poss. backed-over text */ \ ++(yy_lp); \ goto find_rule; \ } #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "yas-grammar.lex" /* Grammar for Y86-64 Assembler */ #include "yas.h" #line 739 "lex.yy.c" #define INITIAL 0 #define ERR 1 #define COM 2 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include <unistd.h> #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (void ); int yyget_debug (void ); void yyset_debug (int debug_flag ); YY_EXTRA_TYPE yyget_extra (void ); void yyset_extra (YY_EXTRA_TYPE user_defined ); FILE *yyget_in (void ); void yyset_in (FILE * in_str ); FILE *yyget_out (void ); void yyset_out (FILE * out_str ); yy_size_t yyget_leng (void ); char *yyget_text (void ); int yyget_lineno (void ); void yyset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif static void yyunput (int c,char *buf_ptr ); #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 16 "yas-grammar.lex" #line 929 "lex.yy.c" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif /* Create the reject buffer large enough to save one state per allowed character. */ if ( ! (yy_state_buf) ) (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE ); if ( ! (yy_state_buf) ) YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); (yy_state_ptr) = (yy_state_buf); *(yy_state_ptr)++ = yy_current_state; yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 257 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; *(yy_state_ptr)++ = yy_current_state; ++yy_cp; } while ( yy_base[yy_current_state] != 692 ); yy_find_action: yy_current_state = *--(yy_state_ptr); (yy_lp) = yy_accept[yy_current_state]; find_rule: /* we branch to this label when backing up */ for ( ; ; ) /* until we find what rule we matched */ { if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] ) { yy_act = yy_acclist[(yy_lp)]; { (yy_full_match) = yy_cp; break; } } --yy_cp; yy_current_state = *--(yy_state_ptr); (yy_lp) = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 1: /* rule 1 can match eol */ YY_RULE_SETUP #line 18 "yas-grammar.lex" { save_line(yytext); REJECT;} /* Snarf input line */ YY_BREAK case 2: /* rule 2 can match eol */ YY_RULE_SETUP #line 19 "yas-grammar.lex" {finish_line(); lineno++;} YY_BREAK case 3: /* rule 3 can match eol */ YY_RULE_SETUP #line 20 "yas-grammar.lex" {finish_line(); lineno++;} YY_BREAK case 4: /* rule 4 can match eol */ YY_RULE_SETUP #line 21 "yas-grammar.lex" {finish_line(); lineno++;} YY_BREAK case 5: /* rule 5 can match eol */ YY_RULE_SETUP #line 22 "yas-grammar.lex" {finish_line(); lineno++;} YY_BREAK case 6: YY_RULE_SETUP #line 24 "yas-grammar.lex" ; YY_BREAK case 7: YY_RULE_SETUP #line 25 "yas-grammar.lex" ; YY_BREAK case 8: YY_RULE_SETUP #line 26 "yas-grammar.lex" add_instr(yytext); YY_BREAK case 9: YY_RULE_SETUP #line 27 "yas-grammar.lex" add_reg(yytext); YY_BREAK case 10: YY_RULE_SETUP #line 28 "yas-grammar.lex" add_num(atoll(yytext)); YY_BREAK case 11: YY_RULE_SETUP #line 29 "yas-grammar.lex" add_num(atollh(yytext)); YY_BREAK case 12: YY_RULE_SETUP #line 30 "yas-grammar.lex" add_punct(*yytext); YY_BREAK case 13: YY_RULE_SETUP #line 31 "yas-grammar.lex" add_ident(yytext); YY_BREAK case 14: YY_RULE_SETUP #line 32 "yas-grammar.lex" {; BEGIN ERR;} YY_BREAK case 15: /* rule 15 can match eol */ YY_RULE_SETUP #line 33 "yas-grammar.lex" {fail("Invalid line"); lineno++; BEGIN 0;} YY_BREAK case 16: YY_RULE_SETUP #line 34 "yas-grammar.lex" ECHO; YY_BREAK #line 1108 "lex.yy.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(ERR): case YY_STATE_EOF(COM): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); (yy_state_ptr) = (yy_state_buf); *(yy_state_ptr)++ = yy_current_state; for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 257 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; *(yy_state_ptr)++ = yy_current_state; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register YY_CHAR yy_c = 1; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 257 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 256); if ( ! yy_is_jam ) *(yy_state_ptr)++ = yy_current_state; return yy_is_jam ? 0 : yy_current_state; } static void yyunput (int c, register char * yy_bp ) { register char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register yy_size_t number_to_move = (yy_n_chars) + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { return yy_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ yy_size_t yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param line_number * */ void yyset_lineno (int line_number ) { yylineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str ) { yyin = in_str ; } void yyset_out (FILE * out_str ) { yyout = out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int bdebug ) { yy_flex_debug = bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; (yy_state_buf) = 0; (yy_state_ptr) = 0; (yy_full_match) = 0; (yy_lp) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; yyfree ( (yy_state_buf) ); (yy_state_buf) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 34 "yas-grammar.lex" unsigned int atoh(const char *s) { return(strtoul(s, NULL, 16)); }

sim/seq/seq-std.hcl

#/* $begin seq-all-hcl */ #################################################################### # HCL Description of Control for Single Cycle Y86-64 Processor SEQ # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2010 # #################################################################### #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'word_t gen_pc(){return 0;}' quote 'int main(int argc, char *argv[])' quote ' {plusmode=0;return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced explicitly ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ##### wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic #################### ##### Fetch stage inputs ##### wordsig pc 'pc' # Program counter ##### Fetch stage computations ##### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig icode 'icode' # Instruction control code wordsig ifun 'ifun' # Instruction function wordsig rA 'ra' # rA field from instruction wordsig rB 'rb' # rB field from instruction wordsig valC 'valc' # Constant from instruction wordsig valP 'valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Decode stage computations ##### wordsig valA 'vala' # Value from register A port wordsig valB 'valb' # Value from register B port ##### Execute stage computations ##### wordsig valE 'vale' # Value computed by ALU boolsig Cnd 'cond' # Branch test ##### Memory stage computations ##### wordsig valM 'valm' # Value read from memory boolsig dmem_error 'dmem_error' # Error signal from data memory #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### # Determine instruction code word icode = [ imem_error: INOP; 1: imem_icode; # Default: get from instruction memory ]; # Determine instruction function word ifun = [ imem_error: FNONE; 1: imem_ifun; # Default: get from instruction memory ]; bool instr_valid = icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Does fetched instruction require a regid byte? bool need_regids = icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; ################ Decode Stage ################################### ## What register should be used as the A source? word srcA = [ icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : rA; icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word srcB = [ icode in { IOPQ, IRMMOVQ, IMRMOVQ } : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word dstE = [ icode in { IRRMOVQ } && Cnd : rB; icode in { IIRMOVQ, IOPQ} : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word dstM = [ icode in { IMRMOVQ, IPOPQ } : rA; 1 : RNONE; # Don't write any register ]; ################ Execute Stage ################################### ## Select input A to ALU word aluA = [ icode in { IRRMOVQ, IOPQ } : valA; icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : valC; icode in { ICALL, IPUSHQ } : -8; icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : valB; icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ icode == IOPQ : ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = icode in { IOPQ }; ################ Memory Stage ################################### ## Set read control signal bool mem_read = icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = icode in { IRMMOVQ, IPUSHQ, ICALL }; ## Select memory address word mem_addr = [ icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : valE; icode in { IPOPQ, IRET } : valA; # Other instructions don't need address ]; ## Select memory input data word mem_data = [ # Value from register icode in { IRMMOVQ, IPUSHQ } : valA; # Return PC icode == ICALL : valP; # Default: Don't write anything ]; ## Determine instruction status word Stat = [ imem_error || dmem_error : SADR; !instr_valid: SINS; icode == IHALT : SHLT; 1 : SAOK; ]; ################ Program Counter Update ############################ ## What address should instruction be fetched at word new_pc = [ # Call. Use instruction constant icode == ICALL : valC; # Taken branch. Use instruction constant icode == IJXX && Cnd : valC; # Completion of RET instruction. Use value from stack icode == IRET : valM; # Default: Use incremented PC 1 : valP; ]; #/* $end seq-all-hcl */

sim/seq/seq-full.hcl

#/* $begin seq-all-hcl */ #################################################################### # HCL Description of Control for Single Cycle Y86-64 Processor SEQ # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2010 # #################################################################### ## Your task is to implement the iaddq instruction ## The file contains a declaration of the icodes ## for iaddq (IIADDQ) ## Your job is to add the rest of the logic to make it work #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'word_t gen_pc(){return 0;}' quote 'int main(int argc, char *argv[])' quote ' {plusmode=0;return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' # Instruction code for iaddq instruction wordsig IIADDQ 'I_IADDQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced explicitly ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ##### wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic #################### ##### Fetch stage inputs ##### wordsig pc 'pc' # Program counter ##### Fetch stage computations ##### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig icode 'icode' # Instruction control code wordsig ifun 'ifun' # Instruction function wordsig rA 'ra' # rA field from instruction wordsig rB 'rb' # rB field from instruction wordsig valC 'valc' # Constant from instruction wordsig valP 'valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Decode stage computations ##### wordsig valA 'vala' # Value from register A port wordsig valB 'valb' # Value from register B port ##### Execute stage computations ##### wordsig valE 'vale' # Value computed by ALU boolsig Cnd 'cond' # Branch test ##### Memory stage computations ##### wordsig valM 'valm' # Value read from memory boolsig dmem_error 'dmem_error' # Error signal from data memory #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### # Determine instruction code word icode = [ imem_error: INOP; 1: imem_icode; # Default: get from instruction memory ]; # Determine instruction function word ifun = [ imem_error: FNONE; 1: imem_ifun; # Default: get from instruction memory ]; bool instr_valid = icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Does fetched instruction require a regid byte? bool need_regids = icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; ################ Decode Stage ################################### ## What register should be used as the A source? word srcA = [ icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : rA; icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word srcB = [ icode in { IOPQ, IRMMOVQ, IMRMOVQ } : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word dstE = [ icode in { IRRMOVQ } && Cnd : rB; icode in { IIRMOVQ, IOPQ} : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word dstM = [ icode in { IMRMOVQ, IPOPQ } : rA; 1 : RNONE; # Don't write any register ]; ################ Execute Stage ################################### ## Select input A to ALU word aluA = [ icode in { IRRMOVQ, IOPQ } : valA; icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : valC; icode in { ICALL, IPUSHQ } : -8; icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : valB; icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ icode == IOPQ : ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = icode in { IOPQ }; ################ Memory Stage ################################### ## Set read control signal bool mem_read = icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = icode in { IRMMOVQ, IPUSHQ, ICALL }; ## Select memory address word mem_addr = [ icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : valE; icode in { IPOPQ, IRET } : valA; # Other instructions don't need address ]; ## Select memory input data word mem_data = [ # Value from register icode in { IRMMOVQ, IPUSHQ } : valA; # Return PC icode == ICALL : valP; # Default: Don't write anything ]; ## Determine instruction status word Stat = [ imem_error || dmem_error : SADR; !instr_valid: SINS; icode == IHALT : SHLT; 1 : SAOK; ]; ################ Program Counter Update ############################ ## What address should instruction be fetched at word new_pc = [ # Call. Use instruction constant icode == ICALL : valC; # Taken branch. Use instruction constant icode == IJXX && Cnd : valC; # Completion of RET instruction. Use value from stack icode == IRET : valM; # Default: Use incremented PC 1 : valP; ]; #/* $end seq-all-hcl */

sim/seq/seq+-std.hcl

#/* $begin seq-all-hcl */ #################################################################### # HCL Description of Control for Single Cycle Y86-64 Processor SEQ+ # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2010 # #################################################################### #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'word_t gen_new_pc(){return 0;}' quote 'int main(int argc, char *argv[])' quote ' {plusmode=1;return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced explicitly ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ##### wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic #################### ##### PC stage inputs ##### ## All of these values are based on those from previous instruction wordsig pIcode 'prev_icode' # Instr. control code wordsig pValC 'prev_valc' # Constant from instruction wordsig pValM 'prev_valm' # Value read from memory wordsig pValP 'prev_valp' # Incremented program counter boolsig pCnd 'prev_bcond' # Condition flag ##### Fetch stage computations ##### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig icode 'icode' # Instruction control code wordsig ifun 'ifun' # Instruction function wordsig rA 'ra' # rA field from instruction wordsig rB 'rb' # rB field from instruction wordsig valC 'valc' # Constant from instruction wordsig valP 'valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Decode stage computations ##### wordsig valA 'vala' # Value from register A port wordsig valB 'valb' # Value from register B port ##### Execute stage computations ##### wordsig valE 'vale' # Value computed by ALU boolsig Cnd 'cond' # Branch test ##### Memory stage computations ##### wordsig valM 'valm' # Value read from memory boolsig dmem_error 'dmem_error' # Error signal from data memory #################################################################### # Control Signal Definitions. # #################################################################### ################ Program Counter Computation ####################### # Compute fetch location for this instruction based on results from # previous instruction. word pc = [ # Call. Use instruction constant pIcode == ICALL : pValC; # Taken branch. Use instruction constant pIcode == IJXX && pCnd : pValC; # Completion of RET instruction. Use value from stack pIcode == IRET : pValM; # Default: Use incremented PC 1 : pValP; ]; #/* $end seq-plus-pc-hcl */ ################ Fetch Stage ################################### # Determine instruction code word icode = [ imem_error: INOP; 1: imem_icode; # Default: get from instruction memory ]; # Determine instruction function word ifun = [ imem_error: FNONE; 1: imem_ifun; # Default: get from instruction memory ]; bool instr_valid = icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Does fetched instruction require a regid byte? bool need_regids = icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; ################ Decode Stage ################################### ## What register should be used as the A source? word srcA = [ icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : rA; icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word srcB = [ icode in { IOPQ, IRMMOVQ, IMRMOVQ } : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word dstE = [ icode in { IRRMOVQ } && Cnd : rB; icode in { IIRMOVQ, IOPQ} : rB; icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word dstM = [ icode in { IMRMOVQ, IPOPQ } : rA; 1 : RNONE; # Don't write any register ]; ################ Execute Stage ################################### ## Select input A to ALU word aluA = [ icode in { IRRMOVQ, IOPQ } : valA; icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : valC; icode in { ICALL, IPUSHQ } : -8; icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : valB; icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ icode == IOPQ : ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = icode in { IOPQ }; ################ Memory Stage ################################### ## Set read control signal bool mem_read = icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = icode in { IRMMOVQ, IPUSHQ, ICALL }; ## Select memory address word mem_addr = [ icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : valE; icode in { IPOPQ, IRET } : valA; # Other instructions don't need address ]; ## Select memory input data word mem_data = [ # Value from register icode in { IRMMOVQ, IPUSHQ } : valA; # Return PC icode == ICALL : valP; # Default: Don't write anything ]; ## Determine instruction status word Stat = [ imem_error || dmem_error : SADR; !instr_valid: SINS; icode == IHALT : SHLT; 1 : SAOK; ]; #/* $end seq-all-hcl */

sim/seq/ssim.c

/*********************************************************************** * * ssim.c - Sequential Y86-64 simulator * * Copyright (c) 2002, 2015. Bryant and D. O'Hallaron, All rights reserved. * May not be used, modified, or copied without permission. ***********************************************************************/ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <unistd.h> #include <string.h> #include "isa.h" #include "sim.h" #define MAXBUF 1024 #ifdef HAS_GUI #include <tk.h> #endif /* HAS_GUI */ #define MAXARGS 128 #define MAXBUF 1024 #define TKARGS 3 /*************** * Begin Globals ***************/ /* Simulator name defined and initialized by the compiled HCL file */ /* according to the -n argument supplied to hcl2c */ extern char simname[]; /* SEQ=0, SEQ+=1. Modified by HCL main() */ int plusmode = 0; /* Parameters modifed by the command line */ int gui_mode = FALSE; /* Run in GUI mode instead of TTY mode? (-g) */ char *object_filename; /* The input object file name. */ FILE *object_file; /* Input file handle */ bool_t verbosity = 2; /* Verbosity level [TTY only] (-v) */ word_t instr_limit = 10000; /* Instruction limit [TTY only] (-l) */ bool_t do_check = FALSE; /* Test with YIS? [TTY only] (-t) */ /************* * End Globals *************/ /*************************** * Begin function prototypes ***************************/ static void usage(char *name); /* Print helpful usage message */ static void run_tty_sim(); /* Run simulator in TTY mode */ #ifdef HAS_GUI void addAppCommands(Tcl_Interp *interp); /* Add application-dependent commands */ #endif /* HAS_GUI */ /************************* * End function prototypes *************************/ /******************************************************************* * Part 1: This part is the initial entry point that handles general * initialization. It parses the command line and does any necessary * setup to run in either TTY or GUI mode, and then starts the * simulation. *******************************************************************/ /* * sim_main - main simulator routine. This function is called from the * main() routine in the HCL file. */ int sim_main(int argc, char **argv) { int i; int c; char *myargv[MAXARGS]; /* Parse the command line arguments */ while ((c = getopt(argc, argv, "htgl:v:")) != -1) { switch(c) { case 'h': usage(argv[0]); break; case 'l': instr_limit = atoll(optarg); break; case 'v': verbosity = atoi(optarg); if (verbosity < 0 || verbosity > 2) { printf("Invalid verbosity %d\n", verbosity); usage(argv[0]); } break; case 't': do_check = TRUE; break; case 'g': gui_mode = TRUE; break; default: printf("Invalid option '%c'\n", c); usage(argv[0]); break; } } /* Do we have too many arguments? */ if (optind < argc - 1) { printf("Too many command line arguments:"); for (i = optind; i < argc; i++) printf(" %s", argv[i]); printf("\n"); usage(argv[0]); } /* The single unflagged argument should be the object file name */ object_filename = NULL; object_file = NULL; if (optind < argc) { object_filename = argv[optind]; object_file = fopen(object_filename, "r"); if (!object_file) { fprintf(stderr, "Couldn't open object file %s\n", object_filename); exit(1); } } /* Run the simulator in GUI mode (-g flag) */ if (gui_mode) { #ifndef HAS_GUI printf("To run in GUI mode, you must recompile with the HAS_GUI constant defined.\n"); exit(1); #endif /* HAS_GUI */ /* In GUI mode, we must specify the object file on command line */ if (!object_file) { printf("Missing object file argument in GUI mode\n"); usage(argv[0]); } /* Build the command line for the GUI simulator */ for (i = 0; i < TKARGS; i++) { if ((myargv[i] = malloc(MAXBUF*sizeof(char))) == NULL) { perror("malloc error"); exit(1); } } strcpy(myargv[0], argv[0]); #if 0 printf("argv[0]=%s\n", argv[0]); { char buf[1000]; getcwd(buf, 1000); printf("cwd=%s\n", buf); } #endif if (plusmode == 0) /* SEQ */ strcpy(myargv[1], "seq.tcl"); else strcpy(myargv[1], "seq+.tcl"); strcpy(myargv[2], object_filename); myargv[3] = NULL; /* Start the GUI simulator */ #ifdef HAS_GUI Tk_Main(TKARGS, myargv, Tcl_AppInit); #endif /* HAS_GUI */ exit(0); } /* Otherwise, run the simulator in TTY mode (no -g flag) */ run_tty_sim(); exit(0); } /* * run_tty_sim - Run the simulator in TTY mode */ static void run_tty_sim() { word_t icount = 0; status = STAT_AOK; cc_t result_cc = 0; word_t byte_cnt = 0; mem_t mem0, reg0; state_ptr isa_state = NULL; /* In TTY mode, the default object file comes from stdin */ if (!object_file) { object_file = stdin; } /* Initializations */ if (verbosity >= 2) sim_set_dumpfile(stdout); sim_init(); /* Emit simulator name */ printf("%s\n", simname); byte_cnt = load_mem(mem, object_file, 1); if (byte_cnt == 0) { fprintf(stderr, "No lines of code found\n"); exit(1); } else if (verbosity >= 2) { printf("%lld bytes of code read\n", byte_cnt); } fclose(object_file); if (do_check) { isa_state = new_state(0); free_mem(isa_state->r); free_mem(isa_state->m); isa_state->m = copy_mem(mem); isa_state->r = copy_mem(reg); isa_state->cc = cc; } mem0 = copy_mem(mem); reg0 = copy_mem(reg); icount = sim_run(instr_limit, &status, &result_cc); if (verbosity > 0) { printf("%lld instructions executed\n", icount); printf("Status = %s\n", stat_name(status)); printf("Condition Codes: %s\n", cc_name(result_cc)); printf("Changed Register State:\n"); diff_reg(reg0, reg, stdout); printf("Changed Memory State:\n"); diff_mem(mem0, mem, stdout); } if (do_check) { byte_t e = STAT_AOK; int step; bool_t match = TRUE; for (step = 0; step < instr_limit && e == STAT_AOK; step++) { e = step_state(isa_state, stdout); } if (diff_reg(isa_state->r, reg, NULL)) { match = FALSE; if (verbosity > 0) { printf("ISA Register != Pipeline Register File\n"); diff_reg(isa_state->r, reg, stdout); } } if (diff_mem(isa_state->m, mem, NULL)) { match = FALSE; if (verbosity > 0) { printf("ISA Memory != Pipeline Memory\n"); diff_mem(isa_state->m, mem, stdout); } } if (isa_state->cc != result_cc) { match = FALSE; if (verbosity > 0) { printf("ISA Cond. Codes (%s) != Pipeline Cond. Codes (%s)\n", cc_name(isa_state->cc), cc_name(result_cc)); } } if (match) { printf("ISA Check Succeeds\n"); } else { printf("ISA Check Fails\n"); } } } /* * usage - print helpful diagnostic information */ static void usage(char *name) { printf("Usage: %s [-htg] [-l m] [-v n] file.yo\n", name); printf("file.yo required in GUI mode, optional in TTY mode (default stdin)\n"); printf(" -h Print this message\n"); printf(" -g Run in GUI mode instead of TTY mode (default TTY)\n"); printf(" -l m Set instruction limit to m [TTY mode only] (default %lld)\n", instr_limit); printf(" -v n Set verbosity level to 0 <= n <= 2 [TTY mode only] (default %d)\n", verbosity); printf(" -t Test result against ISA simulator (yis) [TTY mode only]\n"); exit(0); } /********************************************************* * Part 2: This part contains the core simulator routines. *********************************************************/ /********************** * Begin Part 2 Globals **********************/ /* * Variables related to hardware units in the processor */ mem_t mem; /* Instruction and data memory */ word_t minAddr = 0; word_t memCnt = 0; /* Other processor state */ mem_t reg; /* Register file */ cc_t cc = DEFAULT_CC; /* Condition code register */ cc_t cc_in = DEFAULT_CC; /* Input to condition code register */ /* * SEQ+: Results computed by previous instruction. * Used to compute PC in current instruction */ byte_t prev_icode = I_NOP; byte_t prev_ifun = 0; word_t prev_valc = 0; word_t prev_valm = 0; word_t prev_valp = 0; bool_t prev_bcond = FALSE; byte_t prev_icode_in = I_NOP; byte_t prev_ifun_in = 0; word_t prev_valc_in = 0; word_t prev_valm_in = 0; word_t prev_valp_in = 0; bool_t prev_bcond_in = FALSE; /* Program Counter */ word_t pc = 0; /* Program counter value */ word_t pc_in = 0;/* Input to program counter */ /* Intermediate values */ byte_t imem_icode = I_NOP; byte_t imem_ifun = F_NONE; byte_t icode = I_NOP; word_t ifun = 0; byte_t instr = HPACK(I_NOP, F_NONE); word_t ra = REG_NONE; word_t rb = REG_NONE; word_t valc = 0; word_t valp = 0; bool_t imem_error; bool_t instr_valid; word_t srcA = REG_NONE; word_t srcB = REG_NONE; word_t destE = REG_NONE; word_t destM = REG_NONE; word_t vala = 0; word_t valb = 0; word_t vale = 0; bool_t bcond = FALSE; bool_t cond = FALSE; word_t valm = 0; bool_t dmem_error; bool_t mem_write = FALSE; word_t mem_addr = 0; word_t mem_data = 0; byte_t status = STAT_AOK; /* Values computed by control logic */ word_t gen_pc(); /* SEQ+ */ word_t gen_icode(); word_t gen_ifun(); word_t gen_need_regids(); word_t gen_need_valC(); word_t gen_instr_valid(); word_t gen_srcA(); word_t gen_srcB(); word_t gen_dstE(); word_t gen_dstM(); word_t gen_aluA(); word_t gen_aluB(); word_t gen_alufun(); word_t gen_set_cc(); word_t gen_mem_addr(); word_t gen_mem_data(); word_t gen_mem_read(); word_t gen_mem_write(); word_t gen_Stat(); word_t gen_new_pc(); /* Log file */ FILE *dumpfile = NULL; #ifdef HAS_GUI /* Representations of digits */ static char digits[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; #endif /* HAS_GUI */ /******************** * End Part 2 Globals ********************/ #ifdef HAS_GUI /* Create string in hex/oct/binary format with leading zeros */ /* bpd denotes bits per digit Should be in range 1-4, bpw denotes bits per word.*/ void wstring(uword_t x, int bpd, int bpw, char *str) { int digit; uword_t mask = ((uword_t) 1 << bpd) - 1; for (digit = (bpw-1)/bpd; digit >= 0; digit--) { uword_t val = (x >> (digit * bpd)) & mask; *str++ = digits[val]; } *str = '\0'; } /* used for formatting instructions */ static char status_msg[128]; /* SEQ+ */ static char *format_prev() { char istring[17]; char mstring[17]; char pstring[17]; wstring(prev_valc, 4, 64, istring); wstring(prev_valm, 4, 64, mstring); wstring(prev_valp, 4, 64, pstring); sprintf(status_msg, "%c %s %s %s %s", prev_bcond ? 'Y' : 'N', iname(HPACK(prev_icode, prev_ifun)), istring, mstring, pstring); return status_msg; } static char *format_pc() { char pstring[17]; wstring(pc, 4, 64, pstring); sprintf(status_msg, "%s", pstring); return status_msg; } static char *format_f() { char valcstring[17]; char valpstring[17]; wstring(valc, 4, 64, valcstring); wstring(valp, 4, 64, valpstring); sprintf(status_msg, "%s %s %s %s %s", iname(HPACK(icode, ifun)), reg_name(ra), reg_name(rb), valcstring, valpstring); return status_msg; } static char *format_d() { char valastring[17]; char valbstring[17]; wstring(vala, 4, 64, valastring); wstring(valb, 4, 64, valbstring); sprintf(status_msg, "%s %s %s %s %s %s", valastring, valbstring, reg_name(destE), reg_name(destM), reg_name(srcA), reg_name(srcB)); return status_msg; } static char *format_e() { char valestring[17]; wstring(vale, 4, 64, valestring); sprintf(status_msg, "%c %s", bcond ? 'Y' : 'N', valestring); return status_msg; } static char *format_m() { char valmstring[17]; wstring(valm, 4, 64, valmstring); sprintf(status_msg, "%s", valmstring); return status_msg; } static char *format_npc() { char npcstring[17]; wstring(pc_in, 4, 64, npcstring); sprintf(status_msg, "%s", npcstring); return status_msg; } #endif /* HAS_GUI */ /* Report system state */ static void sim_report() { #ifdef HAS_GUI if (gui_mode) { report_pc(pc); if (plusmode) { report_state("PREV", format_prev()); report_state("PC", format_pc()); } else { report_state("OPC", format_pc()); } report_state("F", format_f()); report_state("D", format_d()); report_state("E", format_e()); report_state("M", format_m()); if (!plusmode) { report_state("NPC", format_npc()); } show_cc(cc); } #endif /* HAS_GUI */ } static int initialized = 0; void sim_init() { /* Create memory and register files */ initialized = 1; mem = init_mem(MEM_SIZE); reg = init_reg(); sim_reset(); clear_mem(mem); } void sim_reset() { if (!initialized) sim_init(); clear_mem(reg); minAddr = 0; memCnt = 0; #ifdef HAS_GUI if (gui_mode) { signal_register_clear(); create_memory_display(); sim_report(); } #endif if (plusmode) { prev_icode = prev_icode_in = I_NOP; prev_ifun = prev_ifun_in = 0; prev_valc = prev_valc_in = 0; prev_valm = prev_valm_in = 0; prev_valp = prev_valp_in = 0; prev_bcond = prev_bcond_in = FALSE; pc = 0; } else { pc_in = 0; } cc = DEFAULT_CC; cc_in = DEFAULT_CC; destE = REG_NONE; destM = REG_NONE; mem_write = FALSE; mem_addr = 0; mem_data = 0; /* Reset intermediate values to clear display */ icode = I_NOP; ifun = 0; instr = HPACK(I_NOP, F_NONE); ra = REG_NONE; rb = REG_NONE; valc = 0; valp = 0; srcA = REG_NONE; srcB = REG_NONE; destE = REG_NONE; destM = REG_NONE; vala = 0; valb = 0; vale = 0; cond = FALSE; bcond = FALSE; valm = 0; sim_report(); } /* Update the processor state */ static void update_state() { if (plusmode) { prev_icode = prev_icode_in; prev_ifun = prev_ifun_in; prev_valc = prev_valc_in; prev_valm = prev_valm_in; prev_valp = prev_valp_in; prev_bcond = prev_bcond_in; } else { pc = pc_in; } cc = cc_in; /* Writeback */ if (destE != REG_NONE) set_reg_val(reg, destE, vale); if (destM != REG_NONE) set_reg_val(reg, destM, valm); if (mem_write) { /* Should have already tested this address */ set_word_val(mem, mem_addr, mem_data); sim_log("Wrote 0x%llx to address 0x%llx\n", mem_data, mem_addr); #ifdef HAS_GUI if (gui_mode) { if (mem_addr % 8 != 0) { /* Just did a misaligned write. Need to display both words */ word_t align_addr = mem_addr & ~0x3; word_t val; get_word_val(mem, align_addr, &val); set_memory(align_addr, val); align_addr+=8; get_word_val(mem, align_addr, &val); set_memory(align_addr, val); } else { set_memory(mem_addr, mem_data); } } #endif /* HAS_GUI */ } } /* Execute one instruction */ /* Return resulting status */ static byte_t sim_step() { word_t aluA; word_t aluB; word_t alufun; status = STAT_AOK; imem_error = dmem_error = FALSE; update_state(); /* Update state from last cycle */ if (plusmode) { pc = gen_pc(); } valp = pc; instr = HPACK(I_NOP, F_NONE); imem_error = !get_byte_val(mem, valp, &instr); if (imem_error) { sim_log("Couldn't fetch at address 0x%llx\n", valp); } imem_icode = HI4(instr); imem_ifun = LO4(instr); icode = gen_icode(); ifun = gen_ifun(); instr_valid = gen_instr_valid(); valp++; if (gen_need_regids()) { byte_t regids; if (get_byte_val(mem, valp, &regids)) { ra = GET_RA(regids); rb = GET_RB(regids); } else { ra = REG_NONE; rb = REG_NONE; status = STAT_ADR; sim_log("Couldn't fetch at address 0x%llx\n", valp); } valp++; } else { ra = REG_NONE; rb = REG_NONE; } if (gen_need_valC()) { if (get_word_val(mem, valp, &valc)) { } else { valc = 0; status = STAT_ADR; sim_log("Couldn't fetch at address 0x%llx\n", valp); } valp+=8; } else { valc = 0; } sim_log("IF: Fetched %s at 0x%llx. ra=%s, rb=%s, valC = 0x%llx\n", iname(HPACK(icode,ifun)), pc, reg_name(ra), reg_name(rb), valc); if (status == STAT_AOK && icode == I_HALT) { status = STAT_HLT; } srcA = gen_srcA(); if (srcA != REG_NONE) { vala = get_reg_val(reg, srcA); } else { vala = 0; } srcB = gen_srcB(); if (srcB != REG_NONE) { valb = get_reg_val(reg, srcB); } else { valb = 0; } cond = cond_holds(cc, ifun); destE = gen_dstE(); destM = gen_dstM(); aluA = gen_aluA(); aluB = gen_aluB(); alufun = gen_alufun(); vale = compute_alu(alufun, aluA, aluB); cc_in = cc; if (gen_set_cc()) cc_in = compute_cc(alufun, aluA, aluB); bcond = cond && (icode == I_JMP); mem_addr = gen_mem_addr(); mem_data = gen_mem_data(); if (gen_mem_read()) { dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm); if (dmem_error) { sim_log("Couldn't read at address 0x%llx\n", mem_addr); } } else valm = 0; mem_write = gen_mem_write(); if (mem_write) { /* Do a test read of the data memory to make sure address is OK */ word_t junk; dmem_error = dmem_error || !get_word_val(mem, mem_addr, &junk); } status = gen_Stat(); if (plusmode) { prev_icode_in = icode; prev_ifun_in = ifun; prev_valc_in = valc; prev_valm_in = valm; prev_valp_in = valp; prev_bcond_in = bcond; } else { /* Update PC */ pc_in = gen_new_pc(); } sim_report(); return status; } /* Run processor until one of following occurs: - An error status is encountered in WB. - max_instr instructions have completed through WB Return number of instructions executed. if statusp nonnull, then will be set to status of final instruction if ccp nonnull, then will be set to condition codes of final instruction */ word_t sim_run(word_t max_instr, byte_t *statusp, cc_t *ccp) { word_t icount = 0; byte_t run_status = STAT_AOK; while (icount < max_instr) { run_status = sim_step(); icount++; if (run_status != STAT_AOK) break; } if (statusp) *statusp = run_status; if (ccp) *ccp = cc; return icount; } /* If dumpfile set nonNULL, lots of status info printed out */ void sim_set_dumpfile(FILE *df) { dumpfile = df; } /* * sim_log dumps a formatted string to the dumpfile, if it exists * accepts variable argument list */ void sim_log( const char *format, ... ) { if (dumpfile) { va_list arg; va_start( arg, format ); vfprintf( dumpfile, format, arg ); va_end( arg ); } } /************************************************************* * Part 3: This part contains simulation control for the TK * simulator. *************************************************************/ #ifdef HAS_GUI /********************** * Begin Part 3 globals **********************/ /* Hack for SunOS */ extern int matherr(); int *tclDummyMathPtr = (int *) matherr; static char tcl_msg[256]; /* Keep track of the TCL Interpreter */ static Tcl_Interp *sim_interp = NULL; static mem_t post_load_mem; /********************** * End Part 3 globals **********************/ /* function prototypes */ int simResetCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); int simRunCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); void addAppCommands(Tcl_Interp *interp); /****************************************************************************** * tcl command definitions ******************************************************************************/ /* Implement command versions of the simulation functions */ int simResetCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { sim_interp = interp; if (argc != 1) { interp->result = "No arguments allowed"; return TCL_ERROR; } sim_reset(); if (post_load_mem) { free_mem(mem); mem = copy_mem(post_load_mem); } interp->result = stat_name(STAT_AOK); return TCL_OK; } int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { FILE *object_file; word_t code_count; sim_interp = interp; if (argc != 2) { interp->result = "One argument required"; return TCL_ERROR; } object_file = fopen(argv[1], "r"); if (!object_file) { sprintf(tcl_msg, "Couldn't open code file '%s'", argv[1]); interp->result = tcl_msg; return TCL_ERROR; } sim_reset(); code_count = load_mem(mem, object_file, 0); post_load_mem = copy_mem(mem); sprintf(tcl_msg, "%lld", code_count); interp->result = tcl_msg; fclose(object_file); return TCL_OK; } int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { FILE *data_file; word_t word_count = 0; interp->result = "Not implemented"; return TCL_ERROR; sim_interp = interp; if (argc != 2) { interp->result = "One argument required"; return TCL_ERROR; } data_file = fopen(argv[1], "r"); if (!data_file) { sprintf(tcl_msg, "Couldn't open data file '%s'", argv[1]); interp->result = tcl_msg; return TCL_ERROR; } sprintf(tcl_msg, "%lld", word_count); interp->result = tcl_msg; fclose(data_file); return TCL_OK; } int simRunCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { word_t step_limit = 1; byte_t run_status; cc_t cc; sim_interp = interp; if (argc > 2) { interp->result = "At most one argument allowed"; return TCL_ERROR; } if (argc >= 2 && (sscanf(argv[1], "%lld", &step_limit) != 1 || step_limit < 0)) { sprintf(tcl_msg, "Cannot run for '%s' cycles!", argv[1]); interp->result = tcl_msg; return TCL_ERROR; } sim_run(step_limit, &run_status, &cc); interp->result = stat_name(run_status); return TCL_OK; } /****************************************************************************** * registering the commands with tcl ******************************************************************************/ void addAppCommands(Tcl_Interp *interp) { sim_interp = interp; Tcl_CreateCommand(interp, "simReset", (Tcl_CmdProc *) simResetCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "simCode", (Tcl_CmdProc *) simLoadCodeCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "simData", (Tcl_CmdProc *) simLoadDataCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "simRun", (Tcl_CmdProc *) simRunCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); } /****************************************************************************** * tcl functionality called from within C ******************************************************************************/ /* Provide mechanism for simulator to update register display */ void signal_register_update(reg_id_t r, word_t val) { int code; sprintf(tcl_msg, "setReg %d %lld 1", (int) r, (word_t) val); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to signal register set\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to generate memory display */ void create_memory_display() { int code; sprintf(tcl_msg, "createMem %lld %lld", minAddr, memCnt); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Command '%s' failed\n", tcl_msg); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } else { word_t i; for (i = 0; i < memCnt && code == TCL_OK; i+=8) { word_t addr = minAddr+i; word_t val; if (!get_word_val(mem, addr, &val)) { fprintf(stderr, "Out of bounds memory display\n"); return; } sprintf(tcl_msg, "setMem %lld %lld", addr, val); code = Tcl_Eval(sim_interp, tcl_msg); } if (code != TCL_OK) { fprintf(stderr, "Couldn't set memory value\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } } /* Provide mechanism for simulator to update memory value */ void set_memory(word_t addr, word_t val) { int code; word_t nminAddr = minAddr; word_t nmemCnt = memCnt; /* First see if we need to expand memory range */ if (memCnt == 0) { nminAddr = addr; nmemCnt = 8; } else if (addr < minAddr) { nminAddr = addr; nmemCnt = minAddr + memCnt - addr; } else if (addr >= minAddr+memCnt) { nmemCnt = addr-minAddr+8; } /* Now make sure nminAddr & nmemCnt are multiples of 16 */ nmemCnt = ((nminAddr & 0xF) + nmemCnt + 0xF) & ~0xF; nminAddr = nminAddr & ~0xF; if (nminAddr != minAddr || nmemCnt != memCnt) { minAddr = nminAddr; memCnt = nmemCnt; create_memory_display(); } else { sprintf(tcl_msg, "setMem %lld %lld", addr, val); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Couldn't set memory value 0x%llx to 0x%llx\n", addr, val); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } } /* Provide mechanism for simulator to update condition code display */ void show_cc(cc_t cc) { int code; sprintf(tcl_msg, "setCC %d %d %d", GET_ZF(cc), GET_SF(cc), GET_OF(cc)); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to display condition codes\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to clear register display */ void signal_register_clear() { int code; code = Tcl_Eval(sim_interp, "clearReg"); if (code != TCL_OK) { fprintf(stderr, "Failed to signal register clear\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to report instructions as they are read in */ void report_line(word_t line_no, word_t addr, char *hex, char *text) { int code; sprintf(tcl_msg, "addCodeLine %lld %lld {%s} {%s}", line_no, addr, hex, text); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to report code line 0x%llx\n", addr); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to report which instruction is being executed */ void report_pc(word_t pc) { int t_status; char addr[18]; char code[20]; Tcl_DString cmd; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, "simLabel ", -1); Tcl_DStringStartSublist(&cmd); sprintf(addr, "%llu", pc); Tcl_DStringAppendElement(&cmd, addr); Tcl_DStringEndSublist(&cmd); Tcl_DStringStartSublist(&cmd); sprintf(code, "%s","*"); Tcl_DStringAppend(&cmd, code, -1); Tcl_DStringEndSublist(&cmd); t_status = Tcl_Eval(sim_interp, Tcl_DStringValue(&cmd)); if (t_status != TCL_OK) { fprintf(stderr, "Failed to report code '%s'\n", code); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Report single line of stage state */ void report_state(char *id, char *txt) { int t_status; sprintf(tcl_msg, "updateStage %s {%s}", id, txt); t_status = Tcl_Eval(sim_interp, tcl_msg); if (t_status != TCL_OK) { fprintf(stderr, "Failed to report processor status\n"); fprintf(stderr, "\tStage %s, status '%s'\n", id, txt); fprintf(stderr, "\tError Message was '%s'\n", sim_interp->result); } } /* * Tcl_AppInit - Called by TCL to perform application-specific initialization. */ int Tcl_AppInit(Tcl_Interp *interp) { /* Tell TCL about the name of the simulator so it can */ /* use it as the title of the main window */ Tcl_SetVar(interp, "simname", simname, TCL_GLOBAL_ONLY); if (Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR; if (Tk_Init(interp) == TCL_ERROR) return TCL_ERROR; Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); /* Call procedure to add new commands */ addAppCommands(interp); /* * Specify a user-specific startup file to invoke if the application * is run interactively. Typically the startup file is "~/.apprc" * where "app" is the name of the application. If this line is deleted * then no user-specific startup file will be run under any conditions. */ Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY); return TCL_OK; } #endif /* HAS_GUI */

sim/seq/sim.h

/********** Defines **************/ /* Get ra out of one byte regid field */ #define GET_RA(r) HI4(r) /* Get rb out of one byte regid field */ #define GET_RB(r) LO4(r) /************ Global state declaration ****************/ /* Determines whether running SEQ or SEQ+ */ extern int plusmode; /* Both instruction and data memory */ extern mem_t mem; /* Keep track of range of addresses that have been written */ extern word_t minAddr; extern word_t memCnt; /* Register file */ extern mem_t reg; /* Condition code register */ extern cc_t cc; /* Program counter */ extern word_t pc; /* For seq+ */ /* Results computed by previous instruction. Used to compute PC in current instruction */ extern byte_t prev_icode; extern byte_t prev_ifun; extern word_t prev_valc; extern word_t prev_valm; extern word_t prev_valp; extern bool_t prev_bcond; /* Intermdiate stage values that must be used by control functions */ extern byte_t imem_icode; extern byte_t imem_ifun; extern byte_t icode; extern word_t ifun; extern word_t ra; extern word_t rb; extern word_t valc; extern word_t valp; extern bool_t imem_error; extern bool_t instr_valid; extern word_t vala; extern word_t valb; extern word_t vale; extern bool_t bcond; extern bool_t cond; extern word_t valm; extern bool_t dmem_error; extern byte_t status; /* Log file */ extern FILE *dumpfile; /* Sets the simulator name (called from main routine in HCL file) */ void set_simname(char *name); /* Initialize simulator */ void sim_init(); /* Reset simulator state, including register, instruction, and data memories */ void sim_reset(); /* Run processor until one of following occurs: - An status error is encountered - max_instr instructions have completed Return number of instructions executed. if statusp nonnull, then will be set to status of final instruction if ccp nonnull, then will be set to condition codes of final instruction */ word_t sim_run(word_t max_instr, byte_t *statusp, cc_t *ccp); /* If dumpfile set nonNULL, lots of status info printed out */ void sim_set_dumpfile(FILE *file); /* * sim_log dumps a formatted string to the dumpfile, if it exists * accepts variable argument list */ void sim_log( const char *format, ... ); /******************* GUI Interface Functions **********************/ #ifdef HAS_GUI void signal_register_clear(); void report_pc(word_t pc); void report_state(char *id, char *txt); void show_cc(cc_t cc); void create_memory_display(); void set_memory(word_t addr, word_t val); #endif

sim/seq/seq.tcl

########################################################################## # Parsing of command line flags # ########################################################################## proc flagVal {flag default} { global argv foreach t $argv { if {[string match "-$flag*" $t]} {return [string range $t 2 end]} } return $default } proc findFlag {flag} { global argv foreach t $argv { if {[string match "-$flag" $t]} {return 1} } return 0 } ########################################################################## # Register File Implementation. Shown as array of 8 columns # ########################################################################## # Font used to display register contents set fontSize [expr 10 * [flagVal "f" 12]] set codeFontSize [expr 10 * [flagVal "c" 10]] set labFontSize [expr 10 * [flagVal "l" 10]] set bigFontSize [expr 10 * [flagVal "b" 16]] set dpyFont "*-courier-medium-r-normal--*-$fontSize-*-*-*-*-*-*" set labFont "*-helvetica-medium-r-normal--*-$labFontSize-*-*-*-*-*-*" set bigLabFont "*-helvetica-bold-r-normal--*-$bigFontSize-*-*-*-*-*-*" set codeFont "*-courier-medium-r-normal--*-$codeFontSize-*-*-*-*-*-*" # Background Color of normal register set normalBg white # Background Color of highlighted register set specialBg LightSkyBlue # Height of titles separating major sections of control panel set sectionHeight 2 # How many rows of code do I display set codeRowCount [flagVal "r" 50] # Keep track of previous highlighted register set lastId -1 proc setReg {id val highlight} { global lastId normalBg specialBg if {$lastId >= 0} { .r.reg$lastId config -bg $normalBg set lastId -1 } if {$id < 0 || $id >= 15} { error "Invalid Register ($id)" } .r.reg$id config -text [format %16x $val] if {$highlight} { uplevel .r.reg$id config -bg $specialBg set lastId $id } } # Clear all registers proc clearReg {} { global lastId normalBg if {$lastId >= 0} { .r.reg$lastId config -bg $normalBg set lastId -1 } for {set i 0} {$i < 8} {incr i 1} { .r.reg$i config -text "" } } # Set all 3 condition codes proc setCC {zv cv ov} { .cc.cc0 config -text [format %d $zv] .cc.cc1 config -text [format %d $cv] .cc.cc2 config -text [format %d $ov] } ### Create display for misc. state frame .flags pack .flags -in . -side bottom ############################################################################## # Status Display # ############################################################################## set simStat "AOK" # Line to display simulation status frame .stat pack .stat -in .flags -side left label .stat.statlab -width 7 -text "Stat" -font $bigLabFont -height $sectionHeight label .stat.statdpy -width 3 -font $dpyFont -relief ridge -bg white -textvariable simStat label .stat.fill -width 6 -text "" pack .stat.statlab .stat.statdpy .stat.fill -in .stat -side left ############################################################################## # Condition Code Display # ############################################################################## # Create Window for condition codes frame .cc pack .cc -in .flags -side right label .cc.lab -text "Condition Codes" -font $bigLabFont -height $sectionHeight pack .cc.lab -in .cc -side left set ccnames [list "Z" "S" "O"] # Create Row of CC Labels for {set i 0} {$i < 3} {incr i 1} { label .cc.lab$i -width 1 -font $dpyFont -text [lindex $ccnames $i] pack .cc.lab$i -in .cc -side left label .cc.cc$i -width 1 -font $dpyFont -relief ridge -bg $normalBg pack .cc.cc$i -in .cc -side left } ############################################################################## # Register Display # ############################################################################## # Create Window for registers frame .r pack .r -in . -side bottom # Following give separate window for register file # toplevel .r # wm title .r "Register File" label .r.lab -text "Register File" -font $bigLabFont -height $sectionHeight pack .r.lab -in .r -side top # Set up top row control panel (disabled) # frame .r.cntl # pack .r.cntl -fill x -in .r # label .r.labreg -text "Register" -width 10 # entry .r.regid -width 3 -relief sunken -textvariable regId -font $dpyFont # label .r.labval -text "Value" -width 10 # entry .r.regval -width 8 -relief sunken -textvariable regVal -font $dpyFont # button .r.doset -text "Set" -command {setReg $regId $regVal 1} -width 6 # button .r.c -text "Clear" -command clearReg -width 6 # pack .r.labreg .r.regid .r.labval .r.regval .r.doset .r.c -in .r.cntl -side left set regnames [list "%rax" "%rcx" "%rdx" "%rbx" "%rsp" "%rbp" "%rsi" "%rdi" "%r8 " "%r9 " "%r10" "%r11" "%r12" "%r13" "%r14" ""] # Create rows of register labels and displays for {set j 0} {$j < 3} {incr j 1} { frame .r.labels$j pack .r.labels$j -side top -in .r for {set c 0} {$c < 5} {incr c 1} { set i [expr $j * 5 + $c] label .r.lab$i -width 16 -font $dpyFont -text [lindex $regnames $i] pack .r.lab$i -in .r.labels$j -side left } # Create Row of Register Entries frame .r.row$j pack .r.row$j -side top -in .r # Create 5 registers for {set c 0} {$c < 5} {incr c 1} { set i [expr $j * 5 + $c] if {$i == 15} { label .r.reg$i -width 16 -font $dpyFont -text "" } else { label .r.reg$i -width 16 -font $dpyFont -relief ridge \ -bg $normalBg } pack .r.reg$i -in .r.row$j -side left } } ############################################################################## # Main Control Panel # ############################################################################## # # Set the simulator name (defined in simname in ssim.c) # as the title of the main window # wm title . $simname # Control Panel for simulator set cntlBW 11 frame .cntl pack .cntl button .cntl.quit -width $cntlBW -text Quit -command exit button .cntl.run -width $cntlBW -text Go -command simGo button .cntl.stop -width $cntlBW -text Stop -command simStop button .cntl.step -width $cntlBW -text Step -command simStep button .cntl.reset -width $cntlBW -text Reset -command simResetAll pack .cntl.quit .cntl.run .cntl.stop .cntl.step .cntl.reset -in .cntl -side left # Simulation speed control scale .spd -label {Simulator Speed (10*log Hz)} -from -10 -to 30 -length 10c \ -orient horizontal -command setSpeed pack .spd # Simulation mode set simMode forward # frame .md # pack .md # radiobutton .md.wedged -text Wedged -variable simMode \ # -value wedged -width 10 -command {setSimMode wedged} # radiobutton .md.stall -text Stall -variable simMode \ # -value stall -width 10 -command {setSimMode stall} # radiobutton .md.forward -text Forward -variable simMode \ # -value forward -width 10 -command {setSimMode forward} # pack .md.wedged .md.stall .md.forward -in .md -side left # simDelay defines #milliseconds for each cycle of simulator # Initial value is 1000ms set simDelay 1000 # Set delay based on rate expressed in log(Hz) proc setSpeed {rate} { global simDelay set simDelay [expr round(1000 / pow(10,$rate/10.0))] } # Global variables controlling simulator execution # Should simulator be running now? set simGoOK 0 proc simStop {} { global simGoOK set simGoOK 0 } proc simStep {} { global simStat set simStat [simRun 1] } proc simGo {} { global simGoOK simDelay simStat set simGoOK 1 # Disable the Go and Step buttons # Enable the Stop button while {$simGoOK} { # run the simulator 1 cycle after $simDelay set simStat [simRun 1] if {$simStat != "AOK" && $simStat != "BUB"} {set simGoOK 0} update } # Disable the Stop button # Enable the Go and Step buttons } ############################################################################## # Processor State display # ############################################################################## # Overall width of pipe register display set procWidth 60 set procHeight 1 set labWidth 8 # Add labeled display to window proc addDisp {win width name} { global dpyFont labFont set lname [string tolower $name] frame $win.$lname pack $win.$lname -in $win -side left label $win.$lname.t -text $name -font $labFont label $win.$lname.c -width $width -font $dpyFont -bg white -relief ridge pack $win.$lname.t $win.$lname.c -in $win.$lname -side top return [list $win.$lname.c] } # Set text in display row proc setDisp {wins txts} { for {set i 0} {$i < [llength $wins] && $i < [llength $txts]} {incr i} { set win [lindex $wins $i] set txt [lindex $txts $i] $win config -text $txt } } frame .p -width $procWidth pack .p -in . -side bottom label .p.lab -text "Processor State" -font $bigLabFont -height $sectionHeight pack .p.lab -in .p -side top label .p.pc -text "PC Update Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White #label .p.wb -text "Writeback Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.mem -text "Memory Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.ex -text "Execute Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.id -text "Decode Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.if -text "Fetch Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White # New PC frame .p.npc # Mem frame .p.m # Execute frame .p.e # Decode frame .p.d # Fetch frame .p.f # Old PC frame .p.opc pack .p.npc .p.pc .p.m .p.mem .p.e .p.ex .p.d .p.id .p.f .p.if .p.opc -in .p -side top -anchor w -expand 1 # Take list of lists, and transpose nesting # Assumes all lists are of same length proc ltranspose {inlist} { set result {} for {set i 0} {$i < [llength [lindex $inlist 0]]} {incr i} { set nlist {} for {set j 0} {$j < [llength $inlist]} {incr j} { set ele [lindex [lindex $inlist $j] $i] set nlist [concat $nlist [list $ele]] } set result [concat $result [list $nlist]] } return $result } # Fields in PC displayed # Total size = 16 set pwins(OPC) [ltranspose [list [addDisp .p.opc 16 PC]]] # Fetch display # Total size = 6+4+4+16+16 = 46 set pwins(F) [ltranspose \ [list [addDisp .p.f 6 Instr] \ [addDisp .p.f 4 rA]\ [addDisp .p.f 4 rB] \ [addDisp .p.f 16 valC] \ [addDisp .p.f 16 valP]]] # Decode Display # Total size = 16+16+4+4+4+4 = 48 set pwins(D) [ltranspose \ [list \ [addDisp .p.d 16 valA] \ [addDisp .p.d 16 valB] \ [addDisp .p.d 4 dstE] \ [addDisp .p.d 4 dstM] \ [addDisp .p.d 4 srcA] \ [addDisp .p.d 4 srcB]]] # Execute Display # Total size = 3+16 = 19 set pwins(E) [ltranspose \ [list [addDisp .p.e 3 Cnd] \ [addDisp .p.e 16 valE]]] # Memory Display # Total size = 16 set pwins(M) [ltranspose \ [list [addDisp .p.m 16 valM]]] # New PC Display # Total Size = 16 set pwins(NPC) [ltranspose \ [list [addDisp .p.npc 16 newPC]]] # update status line for specified proc register proc updateStage {name txts} { set Name [string toupper $name] global pwins set wins [lindex $pwins($Name) 0] setDisp $wins $txts } ########################################################################## # Instruction Display # ########################################################################## toplevel .c wm title .c "Program Code" frame .c.cntl pack .c.cntl -in .c -side top -anchor w label .c.filelab -width 10 -text "File" entry .c.filename -width 20 -relief sunken -textvariable codeFile \ -font $dpyFont -bg white button .c.loadbutton -width $cntlBW -command {loadCode $codeFile} -text Load pack .c.filelab .c.filename .c.loadbutton -in .c.cntl -side left proc clearCode {} { simLabel {} {} destroy .c.t destroy .c.tr } proc createCode {} { # Create Code Structure frame .c.t pack .c.t -in .c -side top -anchor w frame .c.tr pack .c.tr -in .c.t -side top -anchor nw } proc loadCode {file} { # Kill old code window clearCode # Create new one createCode simCode $file simResetAll } # Start with initial code window, even though it will be destroyed. createCode # Add a line of code to the display proc addCodeLine {line addr op text} { global codeRowCount # Create new line in display global codeFont frame .c.tr.$addr pack .c.tr.$addr -in .c.tr -side top -anchor w label .c.tr.$addr.a -width 6 -text [format "0x%x" $addr] -font $codeFont label .c.tr.$addr.i -width 20 -text $op -font $codeFont label .c.tr.$addr.s -width 2 -text "" -font $codeFont -bg white label .c.tr.$addr.t -text $text -font $codeFont pack .c.tr.$addr.a .c.tr.$addr.i .c.tr.$addr.s \ .c.tr.$addr.t -in .c.tr.$addr -side left } # Keep track of which instructions have stage labels set oldAddr {} proc simLabel {addrs labs} { global oldAddr set newAddr {} # Clear away any old labels foreach a $oldAddr { .c.tr.$a.s config -text "" } for {set i 0} {$i < [llength $addrs]} {incr i} { set a [lindex $addrs $i] set t [lindex $labs $i] if {[winfo exists .c.tr.$a]} { .c.tr.$a.s config -text $t set newAddr [concat $newAddr $a] } } set oldAddr $newAddr } proc simResetAll {} { global simStat set simStat "AOK" simReset simLabel {} {} clearMem } ############################################################################### # Memory Display # ############################################################################### toplevel .m wm title .m "Memory Contents" frame .m.t pack .m.t -in .m -side top -anchor w label .m.t.lab -width 6 -font $dpyFont -text " " pack .m.t.lab -in .m.t -side left for {set i 0} {$i < 16} {incr i 8} { label .m.t.a$i -width 16 -font $dpyFont -text [format " 0x---%x" [expr $i % 16]] pack .m.t.a$i -in .m.t -side left } # Keep track of range of addresses currently displayed set minAddr 0 set memCnt 0 set haveMem 0 proc createMem {nminAddr nmemCnt} { global minAddr memCnt haveMem codeFont dpyFont normalBg set minAddr $nminAddr set memCnt $nmemCnt if { $haveMem } { destroy .m.e } # Create Memory Structure frame .m.e set haveMem 1 pack .m.e -in .m -side top -anchor w # Now fill it with values for {set i 0} {$i < $memCnt} {incr i 16} { set addr [expr $minAddr + $i] frame .m.e.r$i pack .m.e.r$i -side bottom -in .m.e label .m.e.r$i.lab -width 6 -font $dpyFont -text [format "0x%.3x-" [expr $addr / 16]] pack .m.e.r$i.lab -in .m.e.r$i -side left for {set j 0} {$j < 16} {incr j 8} { set a [expr $addr + $j] label .m.e.v$a -width 16 -font $dpyFont -relief ridge \ -bg $normalBg pack .m.e.v$a -in .m.e.r$i -side left } } } proc setMem {Addr Val} { global minAddr memCnt if {$Addr < $minAddr || $Addr > [expr $minAddr + $memCnt]} { error "Memory address $Addr out of range" } .m.e.v$Addr config -text [format %16x $Val] } proc clearMem {} { destroy .m.e createMem 0 0 } ############################################################################### # Command Line Initialization # ############################################################################### # Get code file name from input # Find file with specified extension proc findFile {tlist ext} { foreach t $tlist { if {[string match "*.$ext" $t]} {return $t} } return "" } set codeFile [findFile $argv yo] if {$codeFile != ""} { loadCode $codeFile}

sim/seq/seq+.tcl

########################################################################## # Parsing of command line flags # ########################################################################## proc flagVal {flag default} { global argv foreach t $argv { if {[string match "-$flag*" $t]} {return [string range $t 2 end]} } return $default } proc findFlag {flag} { global argv foreach t $argv { if {[string match "-$flag" $t]} {return 1} } return 0 } ########################################################################## # Register File Implementation. Shown as array of 8 columns # ########################################################################## # Font used to display register contents set fontSize [expr 10 * [flagVal "f" 12]] set codeFontSize [expr 10 * [flagVal "c" 10]] set labFontSize [expr 10 * [flagVal "l" 10]] set bigFontSize [expr 10 * [flagVal "b" 16]] set dpyFont "*-courier-medium-r-normal--*-$fontSize-*-*-*-*-*-*" set labFont "*-helvetica-medium-r-normal--*-$labFontSize-*-*-*-*-*-*" set bigLabFont "*-helvetica-bold-r-normal--*-$bigFontSize-*-*-*-*-*-*" set codeFont "*-courier-medium-r-normal--*-$codeFontSize-*-*-*-*-*-*" # Background Color of normal register set normalBg white # Background Color of highlighted register set specialBg LightSkyBlue # Height of titles separating major sections of control panel set sectionHeight 2 # How many rows of code do I display set codeRowCount [flagVal "r" 50] # Keep track of previous highlighted register set lastId -1 proc setReg {id val highlight} { global lastId normalBg specialBg if {$lastId >= 0} { .r.reg$lastId config -bg $normalBg set lastId -1 } if {$id < 0 || $id >= 15} { error "Invalid Register ($id)" } .r.reg$id config -text [format %16x $val] if {$highlight} { uplevel .r.reg$id config -bg $specialBg set lastId $id } } # Clear all registers proc clearReg {} { global lastId normalBg if {$lastId >= 0} { .r.reg$lastId config -bg $normalBg set lastId -1 } for {set i 0} {$i < 8} {incr i 1} { .r.reg$i config -text "" } } # Set all 3 condition codes proc setCC {zv cv ov} { .cc.cc0 config -text [format %d $zv] .cc.cc1 config -text [format %d $cv] .cc.cc2 config -text [format %d $ov] } ### Create display for misc. state frame .flags pack .flags -in . -side bottom ############################################################################## # Status Display # ############################################################################## set simStat "AOK" # Line to display simulation status frame .stat pack .stat -in .flags -side left label .stat.statlab -width 7 -text "Stat" -height $sectionHeight -font $bigLabFont label .stat.statdpy -width 3 -font $dpyFont -relief ridge -bg white -textvariable simStat label .stat.fill -width 6 -text "" pack .stat.statlab .stat.statdpy .stat.fill -in .stat -side left ############################################################################## # Condition Code Display # ############################################################################## # Create Window for condition codes frame .cc pack .cc -in .flags -side right label .cc.lab -text "Condition Codes" -height $sectionHeight -font $bigLabFont pack .cc.lab -in .cc -side left set ccnames [list "Z" "S" "O"] # Create Row of CC Labels for {set i 0} {$i < 3} {incr i 1} { label .cc.lab$i -width 1 -font $dpyFont -text [lindex $ccnames $i] pack .cc.lab$i -in .cc -side left label .cc.cc$i -width 1 -font $dpyFont -relief ridge -bg $normalBg pack .cc.cc$i -in .cc -side left } ############################################################################## # Register Display # ############################################################################## # Create Window for registers frame .r pack .r -in . -side bottom # Following give separate window for register file # toplevel .r # wm title .r "Register File" -height $sectionHeight -font $bigLabFont label .r.lab -text "Register File" -font $bigLabFont -height $sectionHeight pack .r.lab -in .r -side top # Set up top row control panel (disabled) # frame .r.cntl # pack .r.cntl -fill x -in .r # label .r.labreg -text "Register" -width 10 # entry .r.regid -width 3 -relief sunken -textvariable regId -font $dpyFont # label .r.labval -text "Value" -width 10 # entry .r.regval -width 8 -relief sunken -textvariable regVal -font $dpyFont # button .r.doset -text "Set" -command {setReg $regId $regVal 1} -width 6 # button .r.c -text "Clear" -command clearReg -width 6 # pack .r.labreg .r.regid .r.labval .r.regval .r.doset .r.c -in .r.cntl -side left set regnames [list "%rax" "%rcx" "%rdx" "%rbx" "%rsp" "%rbp" "%rsi" "%rdi" "%r8 " "%r9 " "%r10" "%r11" "%r12" "%r13" "%r14" ""] # Create rows of register labels and displays for {set j 0} {$j < 3} {incr j 1} { frame .r.labels$j pack .r.labels$j -side top -in .r for {set c 0} {$c < 5} {incr c 1} { set i [expr $j * 5 + $c] label .r.lab$i -width 16 -font $dpyFont -text [lindex $regnames $i] pack .r.lab$i -in .r.labels$j -side left } # Create Row of Register Entries frame .r.row$j pack .r.row$j -side top -in .r # Create 5 registers for {set c 0} {$c < 5} {incr c 1} { set i [expr $j * 5 + $c] if {$i == 15} { label .r.reg$i -width 16 -font $dpyFont -text "" } else { label .r.reg$i -width 16 -font $dpyFont -relief ridge \ -bg $normalBg } pack .r.reg$i -in .r.row$j -side left } } ############################################################################## # Main Control Panel # ############################################################################## # # Set the simulator name (defined in simname in ssim.c) # as the title of the main window # wm title . $simname #wm title . "Y86-64 Simulator" # Control Panel for simulator set cntlBW 11 frame .cntl pack .cntl button .cntl.quit -width $cntlBW -text Quit -command exit button .cntl.run -width $cntlBW -text Go -command simGo button .cntl.stop -width $cntlBW -text Stop -command simStop button .cntl.step -width $cntlBW -text Step -command simStep button .cntl.reset -width $cntlBW -text Reset -command simResetAll pack .cntl.quit .cntl.run .cntl.stop .cntl.step .cntl.reset -in .cntl -side left # Simulation speed control scale .spd -label {Simulator Speed (10*log Hz)} -from -10 -to 30 -length 10c \ -orient horizontal -command setSpeed pack .spd # Simulation mode set simMode forward # frame .md # pack .md # radiobutton .md.wedged -text Wedged -variable simMode \ # -value wedged -width 10 -command {setSimMode wedged} # radiobutton .md.stall -text Stall -variable simMode \ # -value stall -width 10 -command {setSimMode stall} # radiobutton .md.forward -text Forward -variable simMode \ # -value forward -width 10 -command {setSimMode forward} # pack .md.wedged .md.stall .md.forward -in .md -side left # simDelay defines #milliseconds for each cycle of simulator # Initial value is 1000ms set simDelay 1000 # Set delay based on rate expressed in log(Hz) proc setSpeed {rate} { global simDelay set simDelay [expr round(1000 / pow(10,$rate/10.0))] } # Global variables controlling simulator execution # Should simulator be running now? set simGoOK 0 proc simStop {} { global simGoOK set simGoOK 0 } proc simStep {} { global simStat set simStat [simRun 1] } proc simGo {} { global simGoOK simDelay simStat set simGoOK 1 # Disable the Go and Step buttons # Enable the Stop button while {$simGoOK} { # run the simulator 1 cycle after $simDelay set simStat [simRun 1] if {$simStat != "AOK" && $simStat != "BUB"} {set simGoOK 0} update } # Disable the Stop button # Enable the Go and Step buttons } ############################################################################## # Processor State display # ############################################################################## # Overall width of pipe register display set procWidth 60 set procHeight 1 set labWidth 8 # Add labeled display to window proc addDisp {win width name} { global dpyFont labFont set lname [string tolower $name] frame $win.$lname pack $win.$lname -in $win -side left label $win.$lname.t -text $name -font $labFont label $win.$lname.c -width $width -font $dpyFont -bg white -relief ridge pack $win.$lname.t $win.$lname.c -in $win.$lname -side top return [list $win.$lname.c] } # Set text in display row proc setDisp {wins txts} { for {set i 0} {$i < [llength $wins] && $i < [llength $txts]} {incr i} { set win [lindex $wins $i] set txt [lindex $txts $i] $win config -text $txt } } frame .p -width $procWidth pack .p -in . -side bottom label .p.lab -text "Processor State" -height $sectionHeight -font $bigLabFont pack .p.lab -in .p -side top label .p.mem -text "Memory Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.ex -text "Execute Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.id -text "Decode Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.if -text "Fetch Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White label .p.pcc -text "PC Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White # Mem frame .p.m # Execute frame .p.e # Decode frame .p.d # Fetch frame .p.f # PC frame .p.pc # Prev frame .p.prev pack .p.m .p.mem .p.e .p.ex .p.d .p.id .p.f .p.if .p.pc .p.pcc .p.prev -in .p -side top -anchor w -expand 1 # Take list of lists, and transpose nesting # Assumes all lists are of same length proc ltranspose {inlist} { set result {} for {set i 0} {$i < [llength [lindex $inlist 0]]} {incr i} { set nlist {} for {set j 0} {$j < [llength $inlist]} {incr j} { set ele [lindex [lindex $inlist $j] $i] set nlist [concat $nlist [list $ele]] } set result [concat $result [list $nlist]] } return $result } # Fields in PREV display # Total size = 57 set pwins(PREV) [ltranspose \ [list [addDisp .p.prev 3 pCnd] \ [addDisp .p.prev 6 pInstr] \ [addDisp .p.prev 16 pValC] \ [addDisp .p.prev 16 pValM] \ [addDisp .p.prev 16 pValP]]] # Fields in PC display # Total size = 16 set pwins(PC) [ltranspose [list [addDisp .p.pc 16 PC]]] # Fetch display # Total size = 6+4+4+16+16 = 46 set pwins(F) [ltranspose \ [list [addDisp .p.f 6 Instr] \ [addDisp .p.f 4 rA]\ [addDisp .p.f 4 rB] \ [addDisp .p.f 16 valC] \ [addDisp .p.f 16 valP]]] # Decode Display # Total size = 16+16+4+4+4+4 = 48 set pwins(D) [ltranspose \ [list [addDisp .p.d 16 valA] \ [addDisp .p.d 16 valB] \ [addDisp .p.d 4 dstE] \ [addDisp .p.d 4 dstM] \ [addDisp .p.d 4 srcA] \ [addDisp .p.d 4 srcB]]] # Execute Display # Total size = 3+16 = 19 set pwins(E) [ltranspose \ [list [addDisp .p.e 3 Cnd] \ [addDisp .p.e 16 valE]]] # Memory Display # Total size = 16 set pwins(M) [ltranspose \ [list [addDisp .p.m 16 valM]]] # update status line for specified proc register proc updateStage {name txts} { set Name [string toupper $name] global pwins set wins [lindex $pwins($Name) 0] setDisp $wins $txts } ########################################################################## # Instruction Display # ########################################################################## toplevel .c wm title .c "Program Code" frame .c.cntl pack .c.cntl -in .c -side top -anchor w label .c.filelab -width 10 -text "File" entry .c.filename -width 20 -relief sunken -textvariable codeFile \ -font $dpyFont -bg white button .c.loadbutton -width $cntlBW -command {loadCode $codeFile} -text Load pack .c.filelab .c.filename .c.loadbutton -in .c.cntl -side left proc clearCode {} { simLabel {} {} destroy .c.t destroy .c.tr } proc createCode {} { # Create Code Structure frame .c.t pack .c.t -in .c -side top -anchor w frame .c.tr pack .c.tr -in .c.t -side top -anchor nw } proc loadCode {file} { # Kill old code window clearCode # Create new one createCode simCode $file simResetAll } # Start with initial code window, even though it will be destroyed. createCode # Add a line of code to the display proc addCodeLine {line addr op text} { global codeRowCount # Create new line in display global codeFont frame .c.tr.$addr pack .c.tr.$addr -in .c.tr -side top -anchor w label .c.tr.$addr.a -width 6 -text [format "0x%x" $addr] -font $codeFont label .c.tr.$addr.i -width 20 -text $op -font $codeFont label .c.tr.$addr.s -width 2 -text "" -font $codeFont -bg white label .c.tr.$addr.t -text $text -font $codeFont pack .c.tr.$addr.a .c.tr.$addr.i .c.tr.$addr.s \ .c.tr.$addr.t -in .c.tr.$addr -side left } # Keep track of which instructions have stage labels set oldAddr {} proc simLabel {addrs labs} { global oldAddr set newAddr {} # Clear away any old labels foreach a $oldAddr { .c.tr.$a.s config -text "" } for {set i 0} {$i < [llength $addrs]} {incr i} { set a [lindex $addrs $i] set t [lindex $labs $i] if {[winfo exists .c.tr.$a]} { .c.tr.$a.s config -text $t set newAddr [concat $newAddr $a] } } set oldAddr $newAddr } proc simResetAll {} { global simStat set simStat "AOK" simReset simLabel {} {} clearMem } ############################################################################### # Memory Display # ############################################################################### toplevel .m wm title .m "Memory Contents" frame .m.t pack .m.t -in .m -side top -anchor w label .m.t.lab -width 6 -font $dpyFont -text " " pack .m.t.lab -in .m.t -side left for {set i 0} {$i < 16} {incr i 8} { label .m.t.a$i -width 16 -font $dpyFont -text [format " 0x---%x" [expr $i % 16]] pack .m.t.a$i -in .m.t -side left } # Keep track of range of addresses currently displayed set minAddr 0 set memCnt 0 set haveMem 0 proc createMem {nminAddr nmemCnt} { global minAddr memCnt haveMem codeFont dpyFont normalBg set minAddr $nminAddr set memCnt $nmemCnt if { $haveMem } { destroy .m.e } # Create Memory Structure frame .m.e set haveMem 1 pack .m.e -in .m -side top -anchor w # Now fill it with values for {set i 0} {$i < $memCnt} {incr i 16} { set addr [expr $minAddr + $i] frame .m.e.r$i pack .m.e.r$i -side bottom -in .m.e label .m.e.r$i.lab -width 6 -font $dpyFont -text [format "0x%.3x-" [expr $addr / 16]] pack .m.e.r$i.lab -in .m.e.r$i -side left for {set j 0} {$j < 16} {incr j 8} { set a [expr $addr + $j] label .m.e.v$a -width 16 -font $dpyFont -relief ridge \ -bg $normalBg pack .m.e.v$a -in .m.e.r$i -side left } } } proc setMem {Addr Val} { global minAddr memCnt if {$Addr < $minAddr || $Addr > [expr $minAddr + $memCnt]} { error "Memory address $Addr out of range" } .m.e.v$Addr config -text [format %16x $Val] } proc clearMem {} { destroy .m.e createMem 0 0 } ############################################################################### # Command Line Initialization # ############################################################################### # Get code file name from input # Find file with specified extension proc findFile {tlist ext} { foreach t $tlist { if {[string match "*.$ext" $t]} {return $t} } return "" } set codeFile [findFile $argv yo] if {$codeFile != ""} { loadCode $codeFile}

sim/seq/Makefile

# Modify this line to indicate the default version VERSION=std # Comment this out if you don't have Tcl/Tk on your system GUIMODE=-DHAS_GUI # Modify the following line so that gcc can find the libtcl.so and # libtk.so libraries on your system. You may need to use the -L option # to tell gcc which directory to look in. Comment this out if you # don't have Tcl/Tk. TKLIBS=-L/usr/lib -ltk -ltcl # Modify the following line so that gcc can find the tcl.h and tk.h # header files on your system. Comment this out if you don't have # Tcl/Tk. TKINC=-isystem /usr/include/tcl8.5 # Modify these two lines to choose your compiler and compile time # flags. CC=gcc CFLAGS=-Wall -O2 ################################################## # You shouldn't need to modify anything below here ################################################## MISCDIR=../misc HCL2C=$(MISCDIR)/hcl2c INC=$(TKINC) -I$(MISCDIR) $(GUIMODE) LIBS=$(TKLIBS) -lm YAS=../misc/yas all: ssim # This rule builds the SEQ simulator (ssim) ssim: seq-$(VERSION).hcl ssim.c sim.h $(MISCDIR)/isa.c $(MISCDIR)/isa.h # Building the seq-$(VERSION).hcl version of SEQ $(HCL2C) -n seq-$(VERSION).hcl <seq-$(VERSION).hcl >seq-$(VERSION).c $(CC) $(CFLAGS) $(INC) -o ssim \ seq-$(VERSION).c ssim.c $(MISCDIR)/isa.c $(LIBS) # This rule builds the SEQ+ simulator (ssim+) ssim+: seq+-std.hcl ssim.c sim.h $(MISCDIR)/isa.c $(MISCDIR)/isa.h # Building the seq+-std.hcl version of SEQ+ $(HCL2C) -n seq+-std.hcl <seq+-std.hcl >seq+-std.c $(CC) $(CFLAGS) $(INC) -o ssim+ \ seq+-std.c ssim.c $(MISCDIR)/isa.c $(LIBS) # These are implicit rules for assembling .yo files from .ys files. .SUFFIXES: .ys .yo .ys.yo: $(YAS) $*.ys clean: rm -f ssim ssim+ seq*-*.c *.o *~ *.exe *.yo *.ys

sim/seq/README

/*********************************************************************** * Sequential Y86-64 Simulators * * Copyright (c) 2002, 2010, 2013, 2015 R. Bryant and D. O'Hallaron, * All rights reserved. * May not be used, modified, or copied without permission. ***********************************************************************/ This directory contains the code to construct simulators for SEQ, SEQ+, and the variants of it described in the homework exercises. ************************** 1. Building the simulators ************************** Different versions of the SEQ and SEQ+ simulators can be constructed to use different HCL files when working on the different homework problems. Binary VERSION HCL File Description ssim std seq-std.hcl Standard SEQ simulator described in textbook. ssim full seq-full.hcl For adding iaddq to SEQ. ssim+ std seq+-std.hcl Standard SEQ+ simulator described in textbook. The simulators run in either TTY or GUI mode: o TTY mode: A simulator running in TTY mode prints all information about its runtime behavior on the terminal. It's hard to understand what's going on, but useful for automated testing, and doesn't require any special installation features. o GUI mode: A simulator running in GUI mode uses a fancy graphical user interface. Nice for visualizing and debugging, but requires installation of Tcl/Tk on your system. The Makefile has simple instructions for building TTY or GUI simulators. A TTY simulator runs in TTY mode only. A GUI simulator can run in either TTY mode or GUI mode, according to a command line argument. Once you've configured the Makefile, you can build the different simulators with commands of the form unix> make clean; make ssim VERSION=xxx where "xxx" is one of the versions listed above. For example, to build the version of SEQ described in the CS:APP text based on the control logic in seq-std.hcl, type unix> make clean; make ssim VERSION=std To save typing, you can also set the Makefile's VERSION variable. *********************** 2. Using the simulators *********************** The simulators take identical command line arguments: Usage: ssim [-htg] [-l m] [-v n] file.yo file.yo required in GUI mode, optional in TTY mode (default stdin) -h Print this message -g Run in GUI mode instead of TTY mode (default TTY mode) -l m Set instruction limit to m [TTY mode only] (default 10000) -v n Set verbosity level to 0 <= n <= 2 [TTY mode only] (default 2) -t Test result against the ISA simulator (yis) [TTY model only] ******** 3. Files ******** Makefile Builds the SEQ and SEQ+ simulators Makefile-sim Makefile for student distribution README This file seq+.tcl TCL script for GUI version of SEQ+ seq.tcl TCL script for GUI version of SEQ ssim.c Base sequential simulator code and header file sim.h seq-std.hcl Standard SEQ control logic seq+-std.hcl Standard SEQ+ control logic seq-full.hcl Template for the iaddq problem (4.34-35) seq-full-ans.hcl Solution for the iaddq problems (4.34-35) (Instructor distribution only)

sim/pipe/pipe-1w.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### ## Your task is to modify the design so that on any cycle, only ## one of the two possible (valE and valM) register writes will occur. ## This requires special handling of the popq instruction. ## Overall strategy: IPOPQ passes through pipe, ## treated as stack pointer increment, but not incrementing the PC ## On refetch, modify fetched icode to indicate an instruction "IPOP2", ## which reads from memory. ## This requires modifying the definition of f_icode ## and lots of other changes. Relevant positions to change ## are indicated by comments starting with keyword "1W". #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' # 1W: Special instruction code for second try of popq wordsig IPOP2 'I_POP2' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction ## 1W: Provide access to the PC value for the current instruction wordsig f_pc 'f_pc' # Address of fetched instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction ## 1W: To split ipopq into two cycles, need to be able to ## modify value of icode, ## so that it will be IPOP2 when fetched for second time. word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ f_icode in { IJXX, ICALL } : f_valC; ## 1W: Want to refetch popq one time 1 : f_valP; ]; ################ Decode Stage ###################################### ## W1: Strategy. Decoding of popq rA should be treated the same ## as would iaddq $8, %rsp ## Decoding of pop2 rA treated same as mrmovq -8(%rsp), rA ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## Forward into decode stage for valA word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC d_srcA == e_dstE : e_valE; # Forward valE from execute d_srcA == M_dstM : m_valM; # Forward valM from memory d_srcA == M_dstE : M_valE; # Forward valE from memory d_srcA == W_dstM : W_valM; # Forward valM from write back d_srcA == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalA; # Use value read from register file ]; word d_valB = [ d_srcB == e_dstE : e_valE; # Forward valE from execute d_srcB == M_dstM : m_valM; # Forward valM from memory d_srcB == M_dstE : M_valE; # Forward valE from memory d_srcB == W_dstM : W_valM; # Forward valM from write back d_srcB == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalB; # Use value read from register file ]; ################ Execute Stage ##################################### ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage word e_valA = E_valA; # Pass valA through stage ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ################ Write back stage ################################## ## 1W: For this problem, we introduce a multiplexor that merges ## valE and valM into a single value for writing to register port E. ## DO NOT CHANGE THIS LOGIC ## Merge both write back sources onto register port E ## Set E port register ID word w_dstE = [ ## writing from valM W_dstM != RNONE : W_dstM; 1: W_dstE; ]; ## Set E port value word w_valE = [ W_dstM != RNONE : W_valM; 1: W_valE; ]; ## Disable register port M ## Set M port register ID word w_dstM = RNONE; ## Set M port value word w_valM = 0; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB } || # Stalling at fetch while ret passes through pipeline IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }; bool D_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Stalling at fetch while ret passes through pipeline # but not condition for a load/use hazard !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && # 1W: This condition will change IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB}; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/pipe-broken.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### ## This version does not detect or handle any hazards #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ f_icode in { IJXX, ICALL } : f_valC; 1 : f_valP; ]; ################ Decode Stage ###################################### ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## No forwarding. valA is either valP or value from register file word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC 1 : d_rvalA; # Use value read from register file ]; ## No forwarding. valB is value from register file word d_valB = d_rvalB; ################ Execute Stage ##################################### ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage word e_valA = E_valA; # Pass valA through stage ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ## Set E port register ID word w_dstE = W_dstE; ## Set E port value word w_valE = W_valE; ## Set M port register ID word w_dstM = W_dstM; ## Set M port value word w_valM = W_valM; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = 0; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = 0; bool D_bubble = 0; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = 0; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/pipe-btfnt.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### ## Your task is to modify the design so that conditional branches are ## predicted as being taken when backward and not-taken when forward ## The code here is nearly identical to that for the normal pipeline. ## Comments starting with keyword "BBTFNT" have been added at places ## relevant to the exercise. #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ## BBTFNT: For modified branch prediction, need to distinguish ## conditional vs. unconditional branches ##### Jump conditions referenced explicitly wordsig UNCOND 'C_YES' # Unconditional transfer ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ # BBTFNT: This is where you'll change the branch prediction rule f_icode in { IJXX, ICALL } : f_valC; 1 : f_valP; ]; ################ Decode Stage ###################################### ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## Forward into decode stage for valA word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC d_srcA == e_dstE : e_valE; # Forward valE from execute d_srcA == M_dstM : m_valM; # Forward valM from memory d_srcA == M_dstE : M_valE; # Forward valE from memory d_srcA == W_dstM : W_valM; # Forward valM from write back d_srcA == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalA; # Use value read from register file ]; word d_valB = [ d_srcB == e_dstE : e_valE; # Forward valE from execute d_srcB == M_dstM : m_valM; # Forward valM from memory d_srcB == M_dstE : M_valE; # Forward valE from memory d_srcB == W_dstM : W_valM; # Forward valM from write back d_srcB == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalB; # Use value read from register file ]; ################ Execute Stage ##################################### # BBTFNT: When some branches are predicted as not-taken, you need some # way to get valC into pipeline register M, so that # you can correct for a mispredicted branch. ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage word e_valA = E_valA; # Pass valA through stage ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ## Set E port register ID word w_dstE = W_dstE; ## Set E port value word w_valE = W_valE; ## Set M port register ID word w_dstM = W_dstM; ## Set M port value word w_valM = W_valM; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB } || # Stalling at fetch while ret passes through pipeline IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }; bool D_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # BBTFNT: This condition will change # Stalling at fetch while ret passes through pipeline # but not condition for a load/use hazard !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # BBTFNT: This condition will change # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB}; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/pipe-full.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### ## Your task is to implement the iaddq instruction ## The file contains a declaration of the icodes ## for iaddq (IIADDQ) ## Your job is to add the rest of the logic to make it work #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' # Instruction code for iaddq instruction wordsig IIADDQ 'I_IADDQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ f_icode in { IJXX, ICALL } : f_valC; 1 : f_valP; ]; ################ Decode Stage ###################################### ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## Forward into decode stage for valA word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC d_srcA == e_dstE : e_valE; # Forward valE from execute d_srcA == M_dstM : m_valM; # Forward valM from memory d_srcA == M_dstE : M_valE; # Forward valE from memory d_srcA == W_dstM : W_valM; # Forward valM from write back d_srcA == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalA; # Use value read from register file ]; word d_valB = [ d_srcB == e_dstE : e_valE; # Forward valE from execute d_srcB == M_dstM : m_valM; # Forward valM from memory d_srcB == M_dstE : M_valE; # Forward valE from memory d_srcB == W_dstM : W_valM; # Forward valM from write back d_srcB == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalB; # Use value read from register file ]; ################ Execute Stage ##################################### ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage word e_valA = E_valA; # Pass valA through stage ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ## Set E port register ID word w_dstE = W_dstE; ## Set E port value word w_valE = W_valE; ## Set M port register ID word w_dstM = W_dstM; ## Set M port value word w_valM = W_valM; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB } || # Stalling at fetch while ret passes through pipeline IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }; bool D_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Stalling at fetch while ret passes through pipeline # but not condition for a load/use hazard !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB}; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/pipe-lf.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### ## Your task is to implement load-forwarding, where a value ## read from memory can be stored to memory by the immediately ## following instruction without stalling ## This requires modifying the definition of e_valA ## and relaxing the stall conditions. Relevant sections to change ## are shown in comments containing the keyword "LB" #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ## LF: Carry srcA up to pipeline register M wordsig M_srcA 'ex_mem_curr->srca' # Source A register ID ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ f_icode in { IJXX, ICALL } : f_valC; 1 : f_valP; ]; ################ Decode Stage ###################################### ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## Forward into decode stage for valA word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC d_srcA == e_dstE : e_valE; # Forward valE from execute d_srcA == M_dstM : m_valM; # Forward valM from memory d_srcA == M_dstE : M_valE; # Forward valE from memory d_srcA == W_dstM : W_valM; # Forward valM from write back d_srcA == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalA; # Use value read from register file ]; word d_valB = [ d_srcB == e_dstE : e_valE; # Forward valE from execute d_srcB == M_dstM : m_valM; # Forward valM from memory d_srcB == M_dstE : M_valE; # Forward valE from memory d_srcB == W_dstM : W_valM; # Forward valM from write back d_srcB == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalB; # Use value read from register file ]; ################ Execute Stage ##################################### ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage ## LB: With load forwarding, want to insert valM ## from memory stage when appropriate ## Here it is set to the default used in the normal pipeline word e_valA = [ 1 : E_valA; # Use valA from stage pipe register ]; ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ## Set E port register ID word w_dstE = W_dstE; ## Set E port value word w_valE = W_valE; ## Set M port register ID word w_dstM = W_dstM; ## Set M port value word w_valM = W_valM; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = # Conditions for a load/use hazard ## Set this to the new load/use condition 0 || # Stalling at fetch while ret passes through pipeline IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = # Conditions for a load/use hazard ## Set this to the new load/use condition 0; bool D_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Stalling at fetch while ret passes through pipeline # but not condition for a load/use hazard !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Conditions for a load/use hazard ## Set this to the new load/use condition 0; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/pipe-nobypass.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### ## Your task is to make the pipeline work without using any forwarding ## The normal bypassing logic in the file is disabled. ## You can only change the pipeline control logic at the end of this file. ## The trick is to make the pipeline stall whenever there is a data hazard. #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ f_icode in { IJXX, ICALL } : f_valC; 1 : f_valP; ]; ################ Decode Stage ###################################### ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## DO NOT MODIFY THE FOLLOWING CODE. ## No forwarding. valA is either valP or value from register file word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC 1 : d_rvalA; # Use value read from register file ]; ## No forwarding. valB is value from register file word d_valB = d_rvalB; ################ Execute Stage ##################################### ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage word e_valA = E_valA; # Pass valA through stage ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ## Set E port register ID word w_dstE = W_dstE; ## Set E port value word w_valE = W_valE; ## Set M port register ID word w_dstM = W_dstM; ## Set M port value word w_valM = W_valM; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = # Modify the following to stall the update of pipeline register F 0 || # Stalling at fetch while ret passes through pipeline IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = # Modify the following to stall the instruction in decode 0; bool D_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Stalling at fetch while ret passes through pipeline !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && # but not condition for a generate/use hazard !0 && IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Modify the following to inject bubble into the execute stage 0; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/pipe-nt.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### ## Your task is to modify the design so that conditional branches are ## predicted as being not-taken. The code here is nearly identical ## to that for the normal pipeline. ## Comments starting with keyword "BNT" have been added at places ## relevant to the exercise. #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ## BNT: For modified branch prediction, need to distinguish ## conditional vs. unconditional branches ##### Jump conditions referenced explicitly wordsig UNCOND 'C_YES' # Unconditional transfer ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ # BNT: This is where you'll change the branch prediction rule f_icode in { IJXX, ICALL } : f_valC; 1 : f_valP; ]; ################ Decode Stage ###################################### ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## Forward into decode stage for valA word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC d_srcA == e_dstE : e_valE; # Forward valE from execute d_srcA == M_dstM : m_valM; # Forward valM from memory d_srcA == M_dstE : M_valE; # Forward valE from memory d_srcA == W_dstM : W_valM; # Forward valM from write back d_srcA == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalA; # Use value read from register file ]; word d_valB = [ d_srcB == e_dstE : e_valE; # Forward valE from execute d_srcB == M_dstM : m_valM; # Forward valM from memory d_srcB == M_dstE : M_valE; # Forward valE from memory d_srcB == W_dstM : W_valM; # Forward valM from write back d_srcB == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalB; # Use value read from register file ]; ################ Execute Stage ##################################### # BNT: When some branches are predicted as not-taken, you need some # way to get valC into pipeline register M, so that # you can correct for a mispredicted branch. ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage word e_valA = E_valA; # Pass valA through stage ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ## Set E port register ID word w_dstE = W_dstE; ## Set E port value word w_valE = W_valE; ## Set M port register ID word w_dstM = W_dstM; ## Set M port value word w_valM = W_valM; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB } || # Stalling at fetch while ret passes through pipeline IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }; bool D_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Stalling at fetch while ret passes through pipeline # but not condition for a load/use hazard !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB}; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/pipe-std.hcl

#/* $begin pipe-all-hcl */ #################################################################### # HCL Description of Control for Pipelined Y86-64 Processor # # Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # #################################################################### #################################################################### # C Include's. Don't alter these # #################################################################### quote '#include <stdio.h>' quote '#include "isa.h"' quote '#include "pipeline.h"' quote '#include "stages.h"' quote '#include "sim.h"' quote 'int sim_main(int argc, char *argv[]);' quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' #################################################################### # Declarations. Do not change/remove/delete any of these # #################################################################### ##### Symbolic representation of Y86-64 Instruction Codes ############# wordsig INOP 'I_NOP' wordsig IHALT 'I_HALT' wordsig IRRMOVQ 'I_RRMOVQ' wordsig IIRMOVQ 'I_IRMOVQ' wordsig IRMMOVQ 'I_RMMOVQ' wordsig IMRMOVQ 'I_MRMOVQ' wordsig IOPQ 'I_ALU' wordsig IJXX 'I_JMP' wordsig ICALL 'I_CALL' wordsig IRET 'I_RET' wordsig IPUSHQ 'I_PUSHQ' wordsig IPOPQ 'I_POPQ' ##### Symbolic represenations of Y86-64 function codes ##### wordsig FNONE 'F_NONE' # Default function code ##### Symbolic representation of Y86-64 Registers referenced ##### wordsig RRSP 'REG_RSP' # Stack Pointer wordsig RNONE 'REG_NONE' # Special value indicating "no register" ##### ALU Functions referenced explicitly ########################## wordsig ALUADD 'A_ADD' # ALU should add its arguments ##### Possible instruction status values ##### wordsig SBUB 'STAT_BUB' # Bubble in stage wordsig SAOK 'STAT_AOK' # Normal execution wordsig SADR 'STAT_ADR' # Invalid memory address wordsig SINS 'STAT_INS' # Invalid instruction wordsig SHLT 'STAT_HLT' # Halt instruction encountered ##### Signals that can be referenced by control logic ############## ##### Pipeline Register F ########################################## wordsig F_predPC 'pc_curr->pc' # Predicted value of PC ##### Intermediate Values in Fetch Stage ########################### wordsig imem_icode 'imem_icode' # icode field from instruction memory wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction wordsig f_valP 'if_id_next->valp' # Address of following instruction boolsig imem_error 'imem_error' # Error signal from instruction memory boolsig instr_valid 'instr_valid' # Is fetched instruction valid? ##### Pipeline Register D ########################################## wordsig D_icode 'if_id_curr->icode' # Instruction code wordsig D_rA 'if_id_curr->ra' # rA field from instruction wordsig D_rB 'if_id_curr->rb' # rB field from instruction wordsig D_valP 'if_id_curr->valp' # Incremented PC ##### Intermediate Values in Decode Stage ######################### wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction wordsig d_rvalA 'd_regvala' # valA read from register file wordsig d_rvalB 'd_regvalb' # valB read from register file ##### Pipeline Register E ########################################## wordsig E_icode 'id_ex_curr->icode' # Instruction code wordsig E_ifun 'id_ex_curr->ifun' # Instruction function wordsig E_valC 'id_ex_curr->valc' # Constant data wordsig E_srcA 'id_ex_curr->srca' # Source A register ID wordsig E_valA 'id_ex_curr->vala' # Source A value wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID wordsig E_valB 'id_ex_curr->valb' # Source B value wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID ##### Intermediate Values in Execute Stage ######################### wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) ##### Pipeline Register M ######################### wordsig M_stat 'ex_mem_curr->status' # Instruction status wordsig M_icode 'ex_mem_curr->icode' # Instruction code wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function wordsig M_valA 'ex_mem_curr->vala' # Source A value wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID wordsig M_valE 'ex_mem_curr->vale' # ALU E value wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag boolsig dmem_error 'dmem_error' # Error signal from instruction memory ##### Intermediate Values in Memory Stage ########################## wordsig m_valM 'mem_wb_next->valm' # valM generated by memory wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) ##### Pipeline Register W ########################################## wordsig W_stat 'mem_wb_curr->status' # Instruction status wordsig W_icode 'mem_wb_curr->icode' # Instruction code wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID wordsig W_valE 'mem_wb_curr->vale' # ALU E value wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID wordsig W_valM 'mem_wb_curr->valm' # Memory M value #################################################################### # Control Signal Definitions. # #################################################################### ################ Fetch Stage ################################### ## What address should instruction be fetched at word f_pc = [ # Mispredicted branch. Fetch at incremented PC M_icode == IJXX && !M_Cnd : M_valA; # Completion of RET instruction W_icode == IRET : W_valM; # Default: Use predicted value of PC 1 : F_predPC; ]; ## Determine icode of fetched instruction word f_icode = [ imem_error : INOP; 1: imem_icode; ]; # Determine ifun word f_ifun = [ imem_error : FNONE; 1: imem_ifun; ]; # Is instruction valid? bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; # Determine status code for fetched instruction word f_stat = [ imem_error: SADR; !instr_valid : SINS; f_icode == IHALT : SHLT; 1 : SAOK; ]; # Does fetched instruction require a regid byte? bool need_regids = f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ }; # Does fetched instruction require a constant word? bool need_valC = f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; # Predict next value of PC word f_predPC = [ f_icode in { IJXX, ICALL } : f_valC; 1 : f_valP; ]; ################ Decode Stage ###################################### ## What register should be used as the A source? word d_srcA = [ D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; D_icode in { IPOPQ, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? word d_srcB = [ D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? word d_dstE = [ D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; 1 : RNONE; # Don't write any register ]; ## What register should be used as the M destination? word d_dstM = [ D_icode in { IMRMOVQ, IPOPQ } : D_rA; 1 : RNONE; # Don't write any register ]; ## What should be the A value? ## Forward into decode stage for valA word d_valA = [ D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC d_srcA == e_dstE : e_valE; # Forward valE from execute d_srcA == M_dstM : m_valM; # Forward valM from memory d_srcA == M_dstE : M_valE; # Forward valE from memory d_srcA == W_dstM : W_valM; # Forward valM from write back d_srcA == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalA; # Use value read from register file ]; word d_valB = [ d_srcB == e_dstE : e_valE; # Forward valE from execute d_srcB == M_dstM : m_valM; # Forward valM from memory d_srcB == M_dstE : M_valE; # Forward valE from memory d_srcB == W_dstM : W_valM; # Forward valM from write back d_srcB == W_dstE : W_valE; # Forward valE from write back 1 : d_rvalB; # Use value read from register file ]; ################ Execute Stage ##################################### ## Select input A to ALU word aluA = [ E_icode in { IRRMOVQ, IOPQ } : E_valA; E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; E_icode in { ICALL, IPUSHQ } : -8; E_icode in { IRET, IPOPQ } : 8; # Other instructions don't need ALU ]; ## Select input B to ALU word aluB = [ E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ } : E_valB; E_icode in { IRRMOVQ, IIRMOVQ } : 0; # Other instructions don't need ALU ]; ## Set the ALU function word alufun = [ E_icode == IOPQ : E_ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = E_icode == IOPQ && # State changes only during normal operation !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; ## Generate valA in execute stage word e_valA = E_valA; # Pass valA through stage ## Set dstE to RNONE in event of not-taken conditional move word e_dstE = [ E_icode == IRRMOVQ && !e_Cnd : RNONE; 1 : E_dstE; ]; ################ Memory Stage ###################################### ## Select memory address word mem_addr = [ M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; M_icode in { IPOPQ, IRET } : M_valA; # Other instructions don't need address ]; ## Set read control signal bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; ## Set write control signal bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; #/* $begin pipe-m_stat-hcl */ ## Update the status word m_stat = [ dmem_error : SADR; 1 : M_stat; ]; #/* $end pipe-m_stat-hcl */ ## Set E port register ID word w_dstE = W_dstE; ## Set E port value word w_valE = W_valE; ## Set M port register ID word w_dstM = W_dstM; ## Set M port value word w_valM = W_valM; ## Update processor status word Stat = [ W_stat == SBUB : SAOK; 1 : W_stat; ]; ################ Pipeline Register Control ######################### # Should I stall or inject a bubble into Pipeline Register F? # At most one of these can be true. bool F_bubble = 0; bool F_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB } || # Stalling at fetch while ret passes through pipeline IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register D? # At most one of these can be true. bool D_stall = # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }; bool D_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Stalling at fetch while ret passes through pipeline # but not condition for a load/use hazard !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && IRET in { D_icode, E_icode, M_icode }; # Should I stall or inject a bubble into Pipeline Register E? # At most one of these can be true. bool E_stall = 0; bool E_bubble = # Mispredicted branch (E_icode == IJXX && !e_Cnd) || # Conditions for a load/use hazard E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB}; # Should I stall or inject a bubble into Pipeline Register M? # At most one of these can be true. bool M_stall = 0; # Start injecting bubbles as soon as exception passes through memory stage bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; # Should I stall or inject a bubble into Pipeline Register W? bool W_stall = W_stat in { SADR, SINS, SHLT }; bool W_bubble = 0; #/* $end pipe-all-hcl */

sim/pipe/psim.c

/************************************************************************** * psim.c - Pipelined Y86-64 simulator * * Copyright (c) 2010, 2015. Bryant and D. O'Hallaron, All rights reserved. * May not be used, modified, or copied without permission. **************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <unistd.h> #include <string.h> #include "isa.h" #include "pipeline.h" #include "stages.h" #include "sim.h" #define MAXBUF 1024 #define DEFAULTNAME "Y86-64 Simulator: " #ifdef HAS_GUI #include <tk.h> #endif /* HAS_GUI */ #define MAXARGS 128 #define MAXBUF 1024 #define TKARGS 3 /*************** * Begin Globals ***************/ /* Simulator name defined and initialized by the compiled HCL file */ /* according to the -n argument supplied to hcl2c */ extern char simname[]; /* Parameters modifed by the command line */ int gui_mode = FALSE; /* Run in GUI mode instead of TTY mode? (-g) */ char *object_filename; /* The input object file name. */ FILE *object_file; /* Input file handle */ bool_t verbosity = 2; /* Verbosity level [TTY only] (-v) */ word_t instr_limit = 10000; /* Instruction limit [TTY only] (-l) */ bool_t do_check = FALSE; /* Test with ISA simulator? [TTY only] (-t) */ /************* * End Globals *************/ /*************************** * Begin function prototypes ***************************/ word_t sim_run_pipe(word_t max_instr, word_t max_cycle, byte_t *statusp, cc_t *ccp); static void usage(char *name); /* Print helpful usage message */ static void run_tty_sim(); /* Run simulator in TTY mode */ #ifdef HAS_GUI void addAppCommands(Tcl_Interp *interp); /* Add application-dependent commands */ #endif /* HAS_GUI */ /************************* * End function prototypes *************************/ /******************************************************************* * Part 1: This part is the initial entry point that handles general * initialization. It parses the command line and does any necessary * setup to run in either TTY or GUI mode, and then starts the * simulation. *******************************************************************/ /* * sim_main - main simulator routine. This function is called from the * main() routine in the HCL file. */ int sim_main(int argc, char **argv) { int i; int c; char *myargv[MAXARGS]; /* Parse the command line arguments */ while ((c = getopt(argc, argv, "htgl:v:")) != -1) { switch(c) { case 'h': usage(argv[0]); break; case 'l': instr_limit = atoll(optarg); break; case 'v': verbosity = atoi(optarg); if (verbosity < 0 || verbosity > 2) { printf("Invalid verbosity %d\n", verbosity); usage(argv[0]); } break; case 't': do_check = TRUE; break; case 'g': gui_mode = TRUE; break; default: printf("Invalid option '%c'\n", c); usage(argv[0]); break; } } /* Do we have too many arguments? */ if (optind < argc - 1) { printf("Too many command line arguments:"); for (i = optind; i < argc; i++) printf(" %s", argv[i]); printf("\n"); usage(argv[0]); } /* The single unflagged argument should be the object file name */ object_filename = NULL; object_file = NULL; if (optind < argc) { object_filename = argv[optind]; object_file = fopen(object_filename, "r"); if (!object_file) { fprintf(stderr, "Couldn't open object file %s\n", object_filename); exit(1); } } /* Run the simulator in GUI mode (-g flag) */ if (gui_mode) { #ifndef HAS_GUI printf("To run in GUI mode, you must recompile with the HAS_GUI constant defined.\n"); exit(1); #endif /* HAS_GUI */ /* In GUI mode, we must specify the object file on command line */ if (!object_file) { printf("Missing object file argument in GUI mode\n"); usage(argv[0]); } /* Build the command line for the GUI simulator */ for (i = 0; i < TKARGS; i++) { if ((myargv[i] = malloc(MAXBUF*sizeof(char))) == NULL) { perror("malloc error"); exit(1); } } strcpy(myargv[0], argv[0]); strcpy(myargv[1], "pipe.tcl"); strcpy(myargv[2], object_filename); myargv[3] = NULL; /* Start the GUI simulator */ #ifdef HAS_GUI Tk_Main(TKARGS, myargv, Tcl_AppInit); #endif /* HAS_GUI */ exit(0); } /* Otherwise, run the simulator in TTY mode (no -g flag) */ run_tty_sim(); exit(0); } /* * run_tty_sim - Run the simulator in TTY mode */ static void run_tty_sim() { word_t icount = 0; byte_t run_status = STAT_AOK; cc_t result_cc = 0; word_t byte_cnt = 0; mem_t mem0, reg0; state_ptr isa_state = NULL; /* In TTY mode, the default object file comes from stdin */ if (!object_file) { object_file = stdin; } if (verbosity >= 2) sim_set_dumpfile(stdout); sim_init(); /* Emit simulator name */ if (verbosity >= 2) printf("%s\n", simname); byte_cnt = load_mem(mem, object_file, 1); if (byte_cnt == 0) { fprintf(stderr, "No lines of code found\n"); exit(1); } else if (verbosity >= 2) { printf("%lld bytes of code read\n", byte_cnt); } fclose(object_file); if (do_check) { isa_state = new_state(0); free_mem(isa_state->r); free_mem(isa_state->m); isa_state->m = copy_mem(mem); isa_state->r = copy_mem(reg); isa_state->cc = cc; } mem0 = copy_mem(mem); reg0 = copy_mem(reg); icount = sim_run_pipe(instr_limit, 5*instr_limit, &run_status, &result_cc); if (verbosity > 0) { printf("%lld instructions executed\n", icount); printf("Status = %s\n", stat_name(run_status)); printf("Condition Codes: %s\n", cc_name(result_cc)); printf("Changed Register State:\n"); diff_reg(reg0, reg, stdout); printf("Changed Memory State:\n"); diff_mem(mem0, mem, stdout); } if (do_check) { byte_t e = STAT_AOK; word_t step; bool_t match = TRUE; for (step = 0; step < instr_limit && e == STAT_AOK; step++) { e = step_state(isa_state, stdout); } if (diff_reg(isa_state->r, reg, NULL)) { match = FALSE; if (verbosity > 0) { printf("ISA Register != Pipeline Register File\n"); diff_reg(isa_state->r, reg, stdout); } } if (diff_mem(isa_state->m, mem, NULL)) { match = FALSE; if (verbosity > 0) { printf("ISA Memory != Pipeline Memory\n"); diff_mem(isa_state->m, mem, stdout); } } if (isa_state->cc != result_cc) { match = FALSE; if (verbosity > 0) { printf("ISA Cond. Codes (%s) != Pipeline Cond. Codes (%s)\n", cc_name(isa_state->cc), cc_name(result_cc)); } } if (match) { printf("ISA Check Succeeds\n"); } else { printf("ISA Check Fails\n"); } } /* Emit CPI statistics */ { double cpi = instructions > 0 ? (double) cycles/instructions : 1.0; printf("CPI: %lld cycles/%lld instructions = %.2f\n", cycles, instructions, cpi); } } /* * usage - print helpful diagnostic information */ static void usage(char *name) { printf("Usage: %s [-htg] [-l m] [-v n] file.yo\n", name); printf("file.yo arg required in GUI mode, optional in TTY mode (default stdin)\n"); printf(" -h Print this message\n"); printf(" -g Run in GUI mode instead of TTY mode (default TTY)\n"); printf(" -l m Set instruction limit to m [TTY mode only] (default %lld)\n", instr_limit); printf(" -v n Set verbosity level to 0 <= n <= 2 [TTY mode only] (default %d)\n", verbosity); printf(" -t Test result against ISA simulator [TTY mode only]\n"); exit(0); } /********************************************************* * Part 2: This part contains the core simulator routines. *********************************************************/ /***************** * Part 2 Globals *****************/ /* Performance monitoring */ /* How many cycles have been simulated? */ word_t cycles = 0; /* How many instructions have passed through the WB stage? */ word_t instructions = 0; /* Has simulator gotten past initial bubbles? */ static int starting_up = 1; /* Both instruction and data memory */ mem_t mem; word_t minAddr = 0; word_t memCnt = 0; /* Register file */ mem_t reg; /* Condition code register */ cc_t cc; /* Status code */ stat_t status; /* Pending updates to state */ word_t cc_in = DEFAULT_CC; word_t wb_destE = REG_NONE; word_t wb_valE = 0; word_t wb_destM = REG_NONE; word_t wb_valM = 0; word_t mem_addr = 0; word_t mem_data = 0; bool_t mem_write = FALSE; /* EX Operand sources */ mux_source_t amux = MUX_NONE; mux_source_t bmux = MUX_NONE; /* Current and next states of all pipeline registers */ pc_ptr pc_curr; if_id_ptr if_id_curr; id_ex_ptr id_ex_curr; ex_mem_ptr ex_mem_curr; mem_wb_ptr mem_wb_curr; pc_ptr pc_next; if_id_ptr if_id_next; id_ex_ptr id_ex_next; ex_mem_ptr ex_mem_next; mem_wb_ptr mem_wb_next; /* Intermediate values */ word_t f_pc; byte_t imem_icode; byte_t imem_ifun; bool_t imem_error; bool_t instr_valid; word_t d_regvala; word_t d_regvalb; word_t e_vala; word_t e_valb; bool_t e_bcond; bool_t dmem_error; /* The pipeline state */ pipe_ptr pc_state, if_id_state, id_ex_state, ex_mem_state, mem_wb_state; /* Simulator operating mode */ sim_mode_t sim_mode = S_FORWARD; /* Log file */ FILE *dumpfile = NULL; /***************************************************************************** * reporting code *****************************************************************************/ #ifdef HAS_GUI /* used for formatting instructions */ static char status_msg[128]; static char *format_pc(pc_ptr state) { char pstring[17]; wstring(state->pc, 4, 64, pstring); sprintf(status_msg, "%s %s", stat_name(state->status), pstring); return status_msg; } static char *format_if_id(if_id_ptr state) { char valcstring[17]; char valpstring[17]; wstring(state->valc, 4, 64, valcstring); wstring(state->valp, 4, 64, valpstring); sprintf(status_msg, "%s %s %s %s %s %s", stat_name(state->status), iname(HPACK(state->icode,state->ifun)), reg_name(state->ra), reg_name(state->rb), valcstring, valpstring); return status_msg; } static char *format_id_ex(id_ex_ptr state) { char valcstring[17]; char valastring[17]; char valbstring[17]; wstring(state->valc, 4, 64, valcstring); wstring(state->vala, 4, 64, valastring); wstring(state->valb, 4, 64, valbstring); sprintf(status_msg, "%s %s %s %s %s %s %s %s %s", stat_name(state->status), iname(HPACK(state->icode, state->ifun)), valcstring, valastring, valbstring, reg_name(state->deste), reg_name(state->destm), reg_name(state->srca), reg_name(state->srcb)); return status_msg; } static char *format_ex_mem(ex_mem_ptr state) { char valestring[17]; char valastring[17]; wstring(state->vale, 4, 64, valestring); wstring(state->vala, 4, 64, valastring); sprintf(status_msg, "%s %s %c %s %s %s %s", stat_name(state->status), iname(HPACK(state->icode, state->ifun)), state->takebranch ? 'Y' : 'N', valestring, valastring, reg_name(state->deste), reg_name(state->destm)); return status_msg; } static char *format_mem_wb(mem_wb_ptr state) { char valestring[17]; char valmstring[17]; wstring(state->vale, 4, 64, valestring); wstring(state->valm, 4, 64, valmstring); sprintf(status_msg, "%s %s %s %s %s %s", stat_name(state->status), iname(HPACK(state->icode, state->ifun)), valestring, valmstring, reg_name(state->deste), reg_name(state->destm)); return status_msg; } #endif /* HAS_GUI */ /* Report system state */ static void sim_report() { #ifdef HAS_GUI if (gui_mode) { report_pc(f_pc, pc_curr->status != STAT_BUB, if_id_curr->stage_pc, if_id_curr->status != STAT_BUB, id_ex_curr->stage_pc, id_ex_curr->status != STAT_BUB, ex_mem_curr->stage_pc, ex_mem_curr->status != STAT_BUB, mem_wb_curr->stage_pc, mem_wb_curr->status != STAT_BUB); report_state("F", 0, format_pc(pc_next)); report_state("F", 1, format_pc(pc_curr)); report_state("D", 0, format_if_id(if_id_next)); report_state("D", 1, format_if_id(if_id_curr)); report_state("E", 0, format_id_ex(id_ex_next)); report_state("E", 1, format_id_ex(id_ex_curr)); report_state("M", 0, format_ex_mem(ex_mem_next)); report_state("M", 1, format_ex_mem(ex_mem_curr)); report_state("W", 0, format_mem_wb(mem_wb_next)); report_state("W", 1, format_mem_wb(mem_wb_curr)); /* signal_sources(); */ show_cc(cc); show_stat(status); show_cpi(); } #endif } /***************************************************************************** * pipeline control * These functions can be used to handle hazards *****************************************************************************/ /* bubble stage (has effect at next update) */ void sim_bubble_stage(stage_id_t stage) { switch (stage) { case IF_STAGE : pc_state->op = P_BUBBLE; break; case ID_STAGE : if_id_state->op = P_BUBBLE; break; case EX_STAGE : id_ex_state->op = P_BUBBLE; break; case MEM_STAGE: ex_mem_state->op = P_BUBBLE; break; case WB_STAGE : mem_wb_state->op = P_BUBBLE; break; } } /* stall stage (has effect at next update) */ void sim_stall_stage(stage_id_t stage) { switch (stage) { case IF_STAGE : pc_state->op = P_STALL; break; case ID_STAGE : if_id_state->op = P_STALL; break; case EX_STAGE : id_ex_state->op = P_STALL; break; case MEM_STAGE: ex_mem_state->op = P_STALL; break; case WB_STAGE : mem_wb_state->op = P_STALL; break; } } static int initialized = 0; void sim_init() { /* Create memory and register files */ initialized = 1; mem = init_mem(MEM_SIZE); reg = init_reg(); /* create 5 pipe registers */ pc_state = new_pipe(sizeof(pc_ele), (void *) &bubble_pc); if_id_state = new_pipe(sizeof(if_id_ele), (void *) &bubble_if_id); id_ex_state = new_pipe(sizeof(id_ex_ele), (void *) &bubble_id_ex); ex_mem_state = new_pipe(sizeof(ex_mem_ele), (void *) &bubble_ex_mem); mem_wb_state = new_pipe(sizeof(mem_wb_ele), (void *) &bubble_mem_wb); /* connect them to the pipeline stages */ pc_next = pc_state->next; pc_curr = pc_state->current; if_id_next = if_id_state->next; if_id_curr = if_id_state->current; id_ex_next = id_ex_state->next; id_ex_curr = id_ex_state->current; ex_mem_next = ex_mem_state->next; ex_mem_curr = ex_mem_state->current; mem_wb_next = mem_wb_state->next; mem_wb_curr = mem_wb_state->current; sim_reset(); clear_mem(mem); } void sim_reset() { if (!initialized) sim_init(); clear_pipes(); clear_mem(reg); minAddr = 0; memCnt = 0; starting_up = 1; cycles = instructions = 0; cc = DEFAULT_CC; status = STAT_AOK; #ifdef HAS_GUI if (gui_mode) { signal_register_clear(); create_memory_display(); } #endif amux = bmux = MUX_NONE; cc = cc_in = DEFAULT_CC; wb_destE = REG_NONE; wb_valE = 0; wb_destM = REG_NONE; wb_valM = 0; mem_addr = 0; mem_data = 0; mem_write = FALSE; sim_report(); } /* Update state elements */ /* May need to disable updating of memory & condition codes */ static void update_state(bool_t update_mem, bool_t update_cc) { /* Writeback(s): If either register is REG_NONE, write will have no effect . Order of two writes determines semantics of popl %rsp. According to ISA, %rsp will get popped value */ if (wb_destE != REG_NONE) { sim_log("\tWriteback: Wrote 0x%llx to register %s\n", wb_valE, reg_name(wb_destE)); set_reg_val(reg, wb_destE, wb_valE); } if (wb_destM != REG_NONE) { sim_log("\tWriteback: Wrote 0x%llx to register %s\n", wb_valM, reg_name(wb_destM)); set_reg_val(reg, wb_destM, wb_valM); } /* Memory write */ if (mem_write && !update_mem) { sim_log("\tDisabled write of 0x%llx to address 0x%llx\n", mem_data, mem_addr); } if (update_mem && mem_write) { if (!set_word_val(mem, mem_addr, mem_data)) { sim_log("\tCouldn't write to address 0x%llx\n", mem_addr); } else { sim_log("\tWrote 0x%llx to address 0x%llx\n", mem_data, mem_addr); #ifdef HAS_GUI if (gui_mode) { if (mem_addr % 8 != 0) { /* Just did a misaligned write. Need to display both words */ word_t align_addr = mem_addr & ~0x3; word_t val; get_word_val(mem, align_addr, &val); set_memory(align_addr, val); align_addr+=8; get_word_val(mem, align_addr, &val); set_memory(align_addr, val); } else { set_memory(mem_addr, mem_data); } } #endif } } if (update_cc) cc = cc_in; } /* Text representation of status */ void tty_report(word_t cyc) { sim_log("\nCycle %lld. CC=%s, Stat=%s\n", cyc, cc_name(cc), stat_name(status)); sim_log("F: predPC = 0x%llx\n", pc_curr->pc); sim_log("D: instr = %s, rA = %s, rB = %s, valC = 0x%llx, valP = 0x%llx, Stat = %s\n", iname(HPACK(if_id_curr->icode, if_id_curr->ifun)), reg_name(if_id_curr->ra), reg_name(if_id_curr->rb), if_id_curr->valc, if_id_curr->valp, stat_name(if_id_curr->status)); sim_log("E: instr = %s, valC = 0x%llx, valA = 0x%llx, valB = 0x%llx\n srcA = %s, srcB = %s, dstE = %s, dstM = %s, Stat = %s\n", iname(HPACK(id_ex_curr->icode, id_ex_curr->ifun)), id_ex_curr->valc, id_ex_curr->vala, id_ex_curr->valb, reg_name(id_ex_curr->srca), reg_name(id_ex_curr->srcb), reg_name(id_ex_curr->deste), reg_name(id_ex_curr->destm), stat_name(id_ex_curr->status)); sim_log("M: instr = %s, Cnd = %d, valE = 0x%llx, valA = 0x%llx\n dstE = %s, dstM = %s, Stat = %s\n", iname(HPACK(ex_mem_curr->icode, ex_mem_curr->ifun)), ex_mem_curr->takebranch, ex_mem_curr->vale, ex_mem_curr->vala, reg_name(ex_mem_curr->deste), reg_name(ex_mem_curr->destm), stat_name(ex_mem_curr->status)); sim_log("W: instr = %s, valE = 0x%llx, valM = 0x%llx, dstE = %s, dstM = %s, Stat = %s\n", iname(HPACK(mem_wb_curr->icode, mem_wb_curr->ifun)), mem_wb_curr->vale, mem_wb_curr->valm, reg_name(mem_wb_curr->deste), reg_name(mem_wb_curr->destm), stat_name(mem_wb_curr->status)); } /* Run pipeline for one cycle */ /* Return status of processor */ /* Max_instr indicates maximum number of instructions that want to complete during this simulation run. */ static byte_t sim_step_pipe(word_t max_instr, word_t ccount) { byte_t wb_status = mem_wb_curr->status; byte_t mem_status = mem_wb_next->status; /* How many instructions are ahead of one in wb / ex? */ int ahead_mem = (wb_status != STAT_BUB); int ahead_ex = ahead_mem + (mem_status != STAT_BUB); bool_t update_mem = ahead_mem < max_instr; bool_t update_cc = ahead_ex < max_instr; /* Update program-visible state */ update_state(update_mem, update_cc); /* Update pipe registers */ update_pipes(); tty_report(ccount); if (pc_state->op == P_ERROR) pc_curr->status = STAT_PIP; if (if_id_state->op == P_ERROR) if_id_curr->status = STAT_PIP; if (id_ex_state->op == P_ERROR) id_ex_curr->status = STAT_PIP; if (ex_mem_state->op == P_ERROR) ex_mem_curr->status = STAT_PIP; if (mem_wb_state->op == P_ERROR) mem_wb_curr->status = STAT_PIP; /* Need to do decode after execute & memory stages, and memory stage before execute, in order to propagate forwarding values properly */ do_if_stage(); do_mem_stage(); do_ex_stage(); do_id_wb_stages(); do_stall_check(); #if 0 /* This doesn't seem necessary */ if (id_ex_curr->status != STAT_AOK && id_ex_curr->status != STAT_BUB) { if_id_state->op = P_BUBBLE; id_ex_state->op = P_BUBBLE; } #endif /* Performance monitoring */ if (mem_wb_curr->status != STAT_BUB && mem_wb_curr->icode != I_POP2) { starting_up = 0; instructions++; cycles++; } else { if (!starting_up) cycles++; } sim_report(); return status; } /* Run pipeline until one of following occurs: - An error status is encountered in WB. - max_instr instructions have completed through WB - max_cycle cycles have been simulated Return number of instructions executed. if statusp nonnull, then will be set to status of final instruction if ccp nonnull, then will be set to condition codes of final instruction */ word_t sim_run_pipe(word_t max_instr, word_t max_cycle, byte_t *statusp, cc_t *ccp) { word_t icount = 0; word_t ccount = 0; byte_t run_status = STAT_AOK; while (icount < max_instr && ccount < max_cycle) { run_status = sim_step_pipe(max_instr-icount, ccount); if (run_status != STAT_BUB) icount++; if (run_status != STAT_AOK && run_status != STAT_BUB) break; ccount++; } if (statusp) *statusp = run_status; if (ccp) *ccp = cc; return icount; } /* If dumpfile set nonNULL, lots of status info printed out */ void sim_set_dumpfile(FILE *df) { dumpfile = df; } /* * sim_log dumps a formatted string to the dumpfile, if it exists * accepts variable argument list */ void sim_log( const char *format, ... ) { if (dumpfile) { va_list arg; va_start( arg, format ); vfprintf( dumpfile, format, arg ); va_end( arg ); } } /************************************************************* * Part 3: This part contains support for the GUI simulator *************************************************************/ #ifdef HAS_GUI /********************** * Begin Part 3 globals **********************/ /* Hack for SunOS */ extern int matherr(); int *tclDummyMathPtr = (int *) matherr; static char tcl_msg[256]; /* Keep track of the TCL Interpreter */ static Tcl_Interp *sim_interp = NULL; static mem_t post_load_mem; /********************** * End Part 3 globals **********************/ /****************************************************************************** * function declarations ******************************************************************************/ int simResetCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); int simRunCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); int simModeCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]); void addAppCommands(Tcl_Interp *interp); /****************************************************************************** * tcl command definitions ******************************************************************************/ /* Implement command versions of the simulation functions */ int simResetCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { sim_interp = interp; if (argc != 1) { interp->result = "No arguments allowed"; return TCL_ERROR; } sim_reset(); if (post_load_mem) { free_mem(mem); mem = copy_mem(post_load_mem); } interp->result = stat_name(STAT_AOK); return TCL_OK; } int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { FILE *code_file; word_t code_count; sim_interp = interp; if (argc != 2) { interp->result = "One argument required"; return TCL_ERROR; } code_file = fopen(argv[1], "r"); if (!code_file) { sprintf(tcl_msg, "Couldn't open code file '%s'", argv[1]); interp->result = tcl_msg; return TCL_ERROR; } sim_reset(); code_count = load_mem(mem, code_file, 0); post_load_mem = copy_mem(mem); sprintf(tcl_msg, "%lld", code_count); interp->result = tcl_msg; fclose(code_file); return TCL_OK; } int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { FILE *data_file; word_t word_count = 0; interp->result = "Not implemented"; return TCL_ERROR; sim_interp = interp; if (argc != 2) { interp->result = "One argument required"; return TCL_ERROR; } data_file = fopen(argv[1], "r"); if (!data_file) { sprintf(tcl_msg, "Couldn't open data file '%s'", argv[1]); interp->result = tcl_msg; return TCL_ERROR; } sprintf(tcl_msg, "%lld", word_count); interp->result = tcl_msg; fclose(data_file); return TCL_OK; } int simRunCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { word_t cycle_limit = 1; byte_t status; cc_t cc; sim_interp = interp; if (argc > 2) { interp->result = "At most one argument allowed"; return TCL_ERROR; } if (argc >= 2 && (sscanf(argv[1], "%lld", &cycle_limit) != 1 || cycle_limit < 0)) { sprintf(tcl_msg, "Cannot run for '%s' cycles!", argv[1]); interp->result = tcl_msg; return TCL_ERROR; } sim_run_pipe(cycle_limit + 5, cycle_limit, &status, &cc); interp->result = stat_name(status); return TCL_OK; } int simModeCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) { sim_interp = interp; if (argc != 2) { interp->result = "One argument required"; return TCL_ERROR; } interp->result = argv[1]; if (strcmp(argv[1], "wedged") == 0) sim_mode = S_WEDGED; else if (strcmp(argv[1], "stall") == 0) sim_mode = S_STALL; else if (strcmp(argv[1], "forward") == 0) sim_mode = S_FORWARD; else { sprintf(tcl_msg, "Unknown mode '%s'", argv[1]); interp->result = tcl_msg; return TCL_ERROR; } return TCL_OK; } /****************************************************************************** * registering the commands with tcl ******************************************************************************/ void addAppCommands(Tcl_Interp *interp) { sim_interp = interp; Tcl_CreateCommand(interp, "simReset", (Tcl_CmdProc *) simResetCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "simCode", (Tcl_CmdProc *) simLoadCodeCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "simData", (Tcl_CmdProc *) simLoadDataCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "simRun", (Tcl_CmdProc *) simRunCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "setSimMode", (Tcl_CmdProc *) simModeCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); } /****************************************************************************** * tcl functionality called from within C ******************************************************************************/ /* Provide mechanism for simulator to update register display */ void signal_register_update(reg_id_t r, word_t val) { int code; sprintf(tcl_msg, "setReg %d %lld 1", (int) r, (word_t) val); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to signal register set\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to generate memory display */ void create_memory_display() { int code; sprintf(tcl_msg, "createMem %lld %lld", minAddr, memCnt); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Command '%s' failed\n", tcl_msg); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } else { word_t i; for (i = 0; i < memCnt && code == TCL_OK; i+=8) { word_t addr = minAddr+i; word_t val; if (!get_word_val(mem, addr, &val)) { fprintf(stderr, "Out of bounds memory display\n"); return; } sprintf(tcl_msg, "setMem %lld %lld", addr, val); code = Tcl_Eval(sim_interp, tcl_msg); } if (code != TCL_OK) { fprintf(stderr, "Couldn't set memory value\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } } /* Provide mechanism for simulator to update memory value */ void set_memory(word_t addr, word_t val) { int code; word_t nminAddr = minAddr; word_t nmemCnt = memCnt; /* First see if we need to expand memory range */ if (memCnt == 0) { nminAddr = addr; nmemCnt = 8; } else if (addr < minAddr) { nminAddr = addr; nmemCnt = minAddr + memCnt - addr; } else if (addr >= minAddr+memCnt) { nmemCnt = addr-minAddr+8; } /* Now make sure nminAddr & nmemCnt are multiples of 16 */ nmemCnt = ((nminAddr & 0xF) + nmemCnt + 0xF) & ~0xF; nminAddr = nminAddr & ~0xF; if (nminAddr != minAddr || nmemCnt != memCnt) { minAddr = nminAddr; memCnt = nmemCnt; create_memory_display(); } else { sprintf(tcl_msg, "setMem %lld %lld", addr, val); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Couldn't set memory value 0x%llx to 0x%llx\n", addr, val); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } } /* Provide mechanism for simulator to update condition code display */ void show_cc(cc_t cc) { int code; sprintf(tcl_msg, "setCC %d %d %d", GET_ZF(cc), GET_SF(cc), GET_OF(cc)); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to display condition codes\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to update status display */ void show_stat(stat_t stat) { int code; sprintf(tcl_msg, "showStat %s", stat_name(stat)); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to display status\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to update performance information */ void show_cpi() { int code; double cpi = instructions > 0 ? (double) cycles/instructions : 1.0; sprintf(tcl_msg, "showCPI %lld %lld %.2f", cycles, instructions, (double) cpi); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to display CPI\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } char *rname[] = {"none", "ea", "eb", "me", "wm", "we"}; /* provide mechanism for simulator to specify source registers */ void signal_sources() { int code; sprintf(tcl_msg, "showSources %s %s", rname[amux], rname[bmux]); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to signal forwarding sources\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to clear register display */ void signal_register_clear() { int code; code = Tcl_Eval(sim_interp, "clearReg"); if (code != TCL_OK) { fprintf(stderr, "Failed to signal register clear\n"); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to report instructions as they are read in */ void report_line(word_t line_no, word_t addr, char *hex, char *text) { int code; sprintf(tcl_msg, "addCodeLine %lld %lld {%s} {%s}", line_no, addr, hex, text); code = Tcl_Eval(sim_interp, tcl_msg); if (code != TCL_OK) { fprintf(stderr, "Failed to report code line 0x%llx\n", addr); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Provide mechanism for simulator to report which instructions are in which stages */ void report_pc(unsigned fpc, unsigned char fpcv, unsigned dpc, unsigned char dpcv, unsigned epc, unsigned char epcv, unsigned mpc, unsigned char mpcv, unsigned wpc, unsigned char wpcv) { int status; char addr[10]; char code[12]; Tcl_DString cmd; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, "simLabel ", -1); Tcl_DStringStartSublist(&cmd); if (fpcv) { sprintf(addr, "%u", fpc); Tcl_DStringAppendElement(&cmd, addr); } if (dpcv) { sprintf(addr, "%u", dpc); Tcl_DStringAppendElement(&cmd, addr); } if (epcv) { sprintf(addr, "%u", epc); Tcl_DStringAppendElement(&cmd, addr); } if (mpcv) { sprintf(addr, "%u", mpc); Tcl_DStringAppendElement(&cmd, addr); } if (wpcv) { sprintf(addr, "%u", wpc); Tcl_DStringAppendElement(&cmd, addr); } Tcl_DStringEndSublist(&cmd); Tcl_DStringStartSublist(&cmd); sprintf(code, "%s %s %s %s %s", fpcv ? "F" : "", dpcv ? "D" : "", epcv ? "E" : "", mpcv ? "M" : "", wpcv ? "W" : ""); Tcl_DStringAppend(&cmd, code, -1); Tcl_DStringEndSublist(&cmd); /* Debug fprintf(stderr, "Code '%s'\n", Tcl_DStringValue(&cmd)); */ status = Tcl_Eval(sim_interp, Tcl_DStringValue(&cmd)); if (status != TCL_OK) { fprintf(stderr, "Failed to report pipe code '%s'\n", code); fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); } } /* Report single line of pipeline state */ void report_state(char *id, word_t current, char *txt) { int status; sprintf(tcl_msg, "updateStage %s %lld {%s}", id, current,txt); status = Tcl_Eval(sim_interp, tcl_msg); if (status != TCL_OK) { fprintf(stderr, "Failed to report pipe status\n"); fprintf(stderr, "\tStage %s.%s, status '%s'\n", id, current ? "current" : "next", txt); fprintf(stderr, "\tError Message was '%s'\n", sim_interp->result); } } /* * Tcl_AppInit - Called by TCL to perform application-specific initialization. */ int Tcl_AppInit(Tcl_Interp *interp) { /* Tell TCL about the name of the simulator so it can */ /* use it as the title of the main window */ Tcl_SetVar(interp, "simname", simname, TCL_GLOBAL_ONLY); if (Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR; if (Tk_Init(interp) == TCL_ERROR) return TCL_ERROR; Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); /* Call procedure to add new commands */ addAppCommands(interp); /* * Specify a user-specific startup file to invoke if the application * is run interactively. Typically the startup file is "~/.apprc" * where "app" is the name of the application. If this line is deleted * then no user-specific startup file will be run under any conditions. */ Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY); return TCL_OK; } #endif /* HAS_GUI */ /************************************************************** * Part 4: Code for implementing pipelined processor simulators *************************************************************/ /****************************************************************************** * defines ******************************************************************************/ #define MAX_STAGE 10 /****************************************************************************** * static variables ******************************************************************************/ static pipe_ptr pipes[MAX_STAGE]; static int pipe_count = 0; /****************************************************************************** * function definitions ******************************************************************************/ /* Create new pipe with count bytes of state */ /* bubble_val indicates state corresponding to pipeline bubble */ pipe_ptr new_pipe(int count, void *bubble_val) { pipe_ptr result = (pipe_ptr) malloc(sizeof(pipe_ele)); result->current = malloc(count); result->next = malloc(count); memcpy(result->current, bubble_val, count); memcpy(result->next, bubble_val, count); result->count = count; result->op = P_LOAD; result->bubble_val = bubble_val; pipes[pipe_count++] = result; return result; } /* Update all pipes */ void update_pipes() { int s; for (s = 0; s < pipe_count; s++) { pipe_ptr p = pipes[s]; switch (p->op) { case P_BUBBLE: /* insert a bubble into the next stage */ memcpy(p->current, p->bubble_val, p->count); break; case P_LOAD: /* copy calculated state from previous stage */ memcpy(p->current, p->next, p->count); break; case P_ERROR: /* Like a bubble, but insert error condition */ memcpy(p->current, p->bubble_val, p->count); break; case P_STALL: default: /* do nothing: next stage gets same instr again */ ; } if (p->op != P_ERROR) p->op = P_LOAD; } } /* Set all pipes to bubble values */ void clear_pipes() { int s; for (s = 0; s < pipe_count; s++) { pipe_ptr p = pipes[s]; memcpy(p->current, p->bubble_val, p->count); memcpy(p->next, p->bubble_val, p->count); p->op = P_LOAD; } } /******************** Utility Code *************************/ /* Representations of digits */ static char digits[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; /* Print hex/oct/binary format with leading zeros */ /* bpd denotes bits per digit Should be in range 1-4, pbw denotes bits per word.*/ void wprint(uword_t x, int bpd, int bpw, FILE *fp) { int digit; uword_t mask = ((uword_t) 1 << bpd) - 1; for (digit = (bpw-1)/bpd; digit >= 0; digit--) { uword_t val = (x >> (digit * bpd)) & mask; putc(digits[val], fp); } } /* Create string in hex/oct/binary format with leading zeros */ /* bpd denotes bits per digit Should be in range 1-4, pbw denotes bits per word.*/ void wstring(uword_t x, int bpd, int bpw, char *str) { int digit; uword_t mask = ((uword_t) 1 << bpd) - 1; for (digit = (bpw-1)/bpd; digit >= 0; digit--) { uword_t val = (x >> (digit * bpd)) & mask; *str++ = digits[val]; } *str = '\0'; } /******************************** * Part 5: Stage implementations *********************************/ /*************** Bubbled version of stages *************/ pc_ele bubble_pc = {0,STAT_AOK}; if_id_ele bubble_if_id = { I_NOP, 0, REG_NONE,REG_NONE, 0, 0, STAT_BUB, 0}; id_ex_ele bubble_id_ex = { I_NOP, 0, 0, 0, 0, REG_NONE, REG_NONE, REG_NONE, REG_NONE, STAT_BUB, 0}; ex_mem_ele bubble_ex_mem = { I_NOP, 0, FALSE, 0, 0, REG_NONE, REG_NONE, STAT_BUB, 0}; mem_wb_ele bubble_mem_wb = { I_NOP, 0, 0, 0, REG_NONE, REG_NONE, STAT_BUB, 0}; /*************** Stage Implementations *****************/ word_t gen_f_pc(); word_t gen_need_regids(); word_t gen_need_valC(); word_t gen_instr_valid(); word_t gen_f_predPC(); word_t gen_f_icode(); word_t gen_f_ifun(); word_t gen_f_stat(); word_t gen_instr_valid(); void do_if_stage() { byte_t instr = HPACK(I_NOP, F_NONE); byte_t regids = HPACK(REG_NONE, REG_NONE); word_t valc = 0; word_t valp = f_pc = gen_f_pc(); /* Ready to fetch instruction. Speculatively fetch register byte and immediate word */ imem_error = !get_byte_val(mem, valp, &instr); imem_icode = HI4(instr); imem_ifun = LO4(instr); if (!imem_error) { byte_t junk; /* Make sure can read maximum length instruction */ imem_error = !get_byte_val(mem, valp+5, &junk); } if_id_next->icode = gen_f_icode(); if_id_next->ifun = gen_f_ifun(); if (!imem_error) { sim_log("\tFetch: f_pc = 0x%llx, imem_instr = %s, f_instr = %s\n", f_pc, iname(instr), iname(HPACK(if_id_next->icode, if_id_next->ifun))); } instr_valid = gen_instr_valid(); if (!instr_valid) sim_log("\tFetch: Instruction code 0x%llx invalid\n", instr); if_id_next->status = gen_f_stat(); valp++; if (gen_need_regids()) { get_byte_val(mem, valp, &regids); valp ++; } if_id_next->ra = HI4(regids); if_id_next->rb = LO4(regids); if (gen_need_valC()) { get_word_val(mem, valp, &valc); valp+= 8; } if_id_next->valp = valp; if_id_next->valc = valc; pc_next->pc = gen_f_predPC(); pc_next->status = (if_id_next->status == STAT_AOK) ? STAT_AOK : STAT_BUB; if_id_next->stage_pc = f_pc; } word_t gen_d_srcA(); word_t gen_d_srcB(); word_t gen_d_dstE(); word_t gen_d_dstM(); word_t gen_d_valA(); word_t gen_d_valB(); word_t gen_w_dstE(); word_t gen_w_valE(); word_t gen_w_dstM(); word_t gen_w_valM(); word_t gen_Stat(); /* Implements both ID and WB */ void do_id_wb_stages() { /* Set up write backs. Don't occur until end of cycle */ wb_destE = gen_w_dstE(); wb_valE = gen_w_valE(); wb_destM = gen_w_dstM(); wb_valM = gen_w_valM(); /* Update processor status */ status = gen_Stat(); id_ex_next->srca = gen_d_srcA(); id_ex_next->srcb = gen_d_srcB(); id_ex_next->deste = gen_d_dstE(); id_ex_next->destm = gen_d_dstM(); /* Read the registers */ d_regvala = get_reg_val(reg, id_ex_next->srca); d_regvalb = get_reg_val(reg, id_ex_next->srcb); /* Do forwarding and valA selection */ id_ex_next->vala = gen_d_valA(); id_ex_next->valb = gen_d_valB(); id_ex_next->icode = if_id_curr->icode; id_ex_next->ifun = if_id_curr->ifun; id_ex_next->valc = if_id_curr->valc; id_ex_next->stage_pc = if_id_curr->stage_pc; id_ex_next->status = if_id_curr->status; } word_t gen_alufun(); word_t gen_set_cc(); word_t gen_Bch(); word_t gen_aluA(); word_t gen_aluB(); word_t gen_e_valA(); word_t gen_e_dstE(); void do_ex_stage() { alu_t alufun = gen_alufun(); bool_t setcc = gen_set_cc(); word_t alua, alub; alua = gen_aluA(); alub = gen_aluB(); e_bcond = cond_holds(cc, id_ex_curr->ifun); ex_mem_next->takebranch = e_bcond; if (id_ex_curr->icode == I_JMP) sim_log("\tExecute: instr = %s, cc = %s, branch %staken\n", iname(HPACK(id_ex_curr->icode, id_ex_curr->ifun)), cc_name(cc), ex_mem_next->takebranch ? "" : "not "); /* Perform the ALU operation */ word_t aluout = compute_alu(alufun, alua, alub); ex_mem_next->vale = aluout; sim_log("\tExecute: ALU: %c 0x%llx 0x%llx --> 0x%llx\n", op_name(alufun), alua, alub, aluout); if (setcc) { cc_in = compute_cc(alufun, alua, alub); sim_log("\tExecute: New cc = %s\n", cc_name(cc_in)); } ex_mem_next->icode = id_ex_curr->icode; ex_mem_next->ifun = id_ex_curr->ifun; ex_mem_next->vala = gen_e_valA(); ex_mem_next->deste = gen_e_dstE(); ex_mem_next->destm = id_ex_curr->destm; ex_mem_next->srca = id_ex_curr->srca; ex_mem_next->status = id_ex_curr->status; ex_mem_next->stage_pc = id_ex_curr->stage_pc; } /* Functions defined using HCL */ word_t gen_mem_addr(); word_t gen_mem_read(); word_t gen_mem_write(); word_t gen_m_stat(); void do_mem_stage() { bool_t read = gen_mem_read(); word_t valm = 0; mem_addr = gen_mem_addr(); mem_data = ex_mem_curr->vala; mem_write = gen_mem_write(); dmem_error = FALSE; if (read) { dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm); if (!dmem_error) sim_log("\tMemory: Read 0x%llx from 0x%llx\n", valm, mem_addr); } if (mem_write) { word_t sink; /* Do a read of address just to check validity */ dmem_error = dmem_error || !get_word_val(mem, mem_addr, &sink); if (dmem_error) sim_log("\tMemory: Invalid address 0x%llx\n", mem_addr); } mem_wb_next->icode = ex_mem_curr->icode; mem_wb_next->ifun = ex_mem_curr->ifun; mem_wb_next->vale = ex_mem_curr->vale; mem_wb_next->valm = valm; mem_wb_next->deste = ex_mem_curr->deste; mem_wb_next->destm = ex_mem_curr->destm; mem_wb_next->status = gen_m_stat(); mem_wb_next->stage_pc = ex_mem_curr->stage_pc; } /* Set stalling conditions for different stages */ word_t gen_F_stall(), gen_F_bubble(); word_t gen_D_stall(), gen_D_bubble(); word_t gen_E_stall(), gen_E_bubble(); word_t gen_M_stall(), gen_M_bubble(); word_t gen_W_stall(), gen_W_bubble(); p_stat_t pipe_cntl(char *name, word_t stall, word_t bubble) { if (stall) { if (bubble) { sim_log("%s: Conflicting control signals for pipe register\n", name); return P_ERROR; } else return P_STALL; } else { return bubble ? P_BUBBLE : P_LOAD; } } void do_stall_check() { pc_state->op = pipe_cntl("PC", gen_F_stall(), gen_F_bubble()); if_id_state->op = pipe_cntl("ID", gen_D_stall(), gen_D_bubble()); id_ex_state->op = pipe_cntl("EX", gen_E_stall(), gen_E_bubble()); ex_mem_state->op = pipe_cntl("MEM", gen_M_stall(), gen_M_bubble()); mem_wb_state->op = pipe_cntl("WB", gen_W_stall(), gen_W_bubble()); }

sim/pipe/pipe.tcl

########################################################################## # Parsing of command line flags # ########################################################################## proc flagVal {flag default} { global argv foreach t $argv { if {[string match "-$flag*" $t]} {return [string range $t 2 end]} } return $default } proc findFlag {flag} { global argv foreach t $argv { if {[string match "-$flag" $t]} {return 1} } return 0 } ########################################################################## # Register File Implementation. Shown as array of 3 X 5 # ########################################################################## # Font used to display register contents set fontSize [expr 10 * [flagVal "f" 12]] set codeFontSize [expr 10 * [flagVal "c" 10]] set labFontSize [expr 10 * [flagVal "l" 10]] set bigFontSize [expr 10 * [flagVal "b" 16]] set dpyFont "*-courier-medium-r-normal--*-$fontSize-*-*-*-*-*-*" set labFont "*-helvetica-medium-r-normal--*-$labFontSize-*-*-*-*-*-*" set bigLabFont "*-helvetica-bold-r-normal--*-$bigFontSize-*-*-*-*-*-*" set codeFont "*-courier-medium-r-normal--*-$codeFontSize-*-*-*-*-*-*" # Background Color of normal register set normalBg white # Background Color of highlighted register set specialBg LightSkyBlue # Height of titles separating major sections of control panel set sectionHeight 2 # How many rows of code do I display set codeRowCount [flagVal "r" 50] # Keep track of previous highlighted register set lastId -1 proc setReg {id val highlight} { global lastId normalBg specialBg if {$lastId >= 0} { .r.reg$lastId config -bg $normalBg set lastId -1 } if {$id < 0 || $id >= 15} { error "Invalid Register ($id)" } .r.reg$id config -text [format %16x $val] if {$highlight} { uplevel .r.reg$id config -bg $specialBg set lastId $id } } # Clear all registers proc clearReg {} { global lastId normalBg if {$lastId >= 0} { .r.reg$lastId config -bg $normalBg set lastId -1 } for {set i 0} {$i < 8} {incr i 1} { .r.reg$i config -text "" } } # Set all 3 condition codes proc setCC {zv cv ov} { .cc.cc0 config -text [format %d $zv] .cc.cc1 config -text [format %d $cv] .cc.cc2 config -text [format %d $ov] } # Set CPI display proc showCPI {cycles instructions cpi} { .cpi.cyc config -text [format %d $cycles] .cpi.instr config -text [format %d $instructions] .cpi.cpi config -text [format %.2f $cpi] } # Set status display proc showStat {s} { .stat.val config -text $s } ############################################################################## # CPI Display ############################################################################## # Create Window for CPI display frame .cpi pack .cpi -in . -side bottom label .cpi.lab -text "Performance" -font $bigLabFont -height $sectionHeight pack .cpi.lab -in .cpi -side left label .cpi.clab -text "Cycles" -font $labFont pack .cpi.clab -in .cpi -side left label .cpi.cyc -text "0" -width 6 -font $dpyFont -relief ridge -bg $normalBg pack .cpi.cyc -in .cpi -side left label .cpi.ilab -text "Instructions" -font $labFont pack .cpi.ilab -in .cpi -side left label .cpi.instr -text "0" -width 6 -font $dpyFont -relief ridge -bg $normalBg pack .cpi.instr -in .cpi -side left label .cpi.cpilab -text "CPI" -font $labFont pack .cpi.cpilab -in .cpi -side left label .cpi.cpi -text "1.0" -width 5 -font $dpyFont -relief ridge -bg $normalBg pack .cpi.cpi -in .cpi -side left ############################################################################## # Status Display # ############################################################################## # Create Window for processor status (packed next to condition codes) frame .stat pack .stat -in . -side bottom label .stat.lab -text "Stat" -width 7 -font $bigLabFont -height $sectionHeight label .stat.val -width 3 -font $dpyFont -relief ridge -bg $normalBg label .stat.fill -width 6 -text "" pack .stat.lab .stat.val .stat.fill -in .stat -side left ############################################################################## # Condition Code Display # ############################################################################## # Create Window for condition codes frame .cc pack .cc -in .stat -side left label .cc.lab -text "Condition Codes" -font $bigLabFont -height $sectionHeight pack .cc.lab -in .cc -side left set ccnames [list "Z" "S" "O"] # Create Row of CC Labels for {set i 0} {$i < 3} {incr i 1} { label .cc.lab$i -width 1 -font $dpyFont -text [lindex $ccnames $i] pack .cc.lab$i -in .cc -side left label .cc.cc$i -width 1 -font $dpyFont -relief ridge -bg $normalBg pack .cc.cc$i -in .cc -side left } ############################################################################## # Register Display # ############################################################################## # Create Window for registers frame .r pack .r -in . -side bottom # Following give separate window for register file # toplevel .r # wm title .r "Register File" label .r.lab -text "Register File" -font $bigLabFont -height $sectionHeight pack .r.lab -in .r -side top # Set up top row control panel (disabled) # frame .r.cntl # pack .r.cntl -fill x -in .r # label .r.labreg -text "Register" -width 10 # entry .r.regid -width 3 -relief sunken -textvariable regId -font $dpyFont # label .r.labval -text "Value" -width 10 # entry .r.regval -width 8 -relief sunken -textvariable regVal -font $dpyFont # button .r.doset -text "Set" -command {setReg $regId $regVal 1} -width 6 # button .r.c -text "Clear" -command clearReg -width 6 # pack .r.labreg .r.regid .r.labval .r.regval .r.doset .r.c -in .r.cntl -side left set regnames [list "%rax" "%rcx" "%rdx" "%rbx" "%rsp" "%rbp" "%rsi" "%rdi" "%r8 " "%r9 " "%r10" "%r11" "%r12" "%r13" "%r14" ""] # Create rows of register labels and displays for {set j 0} {$j < 3} {incr j 1} { frame .r.labels$j pack .r.labels$j -side top -in .r for {set c 0} {$c < 5} {incr c 1} { set i [expr $j * 5 + $c] label .r.lab$i -width 16 -font $dpyFont -text [lindex $regnames $i] pack .r.lab$i -in .r.labels$j -side left } # Create Row of Register Entries frame .r.row$j pack .r.row$j -side top -in .r # Create 5 registers for {set c 0} {$c < 5} {incr c 1} { set i [expr $j * 5 + $c] if {$i == 15} { label .r.reg$i -width 16 -font $dpyFont -text "" } else { label .r.reg$i -width 16 -font $dpyFont -relief ridge \ -bg $normalBg } pack .r.reg$i -in .r.row$j -side left } } ############################################################################## # Main Control Panel # ############################################################################## # # Set the simulator name (defined in simname in ssim.c) # as the title of the main window # wm title . $simname # Control Panel for simulator set cntlBW 12 frame .cntl pack .cntl button .cntl.quit -width $cntlBW -text Quit -command exit button .cntl.run -width $cntlBW -text Go -command simGo button .cntl.stop -width $cntlBW -text Stop -command simStop button .cntl.step -width $cntlBW -text Step -command simStep button .cntl.reset -width $cntlBW -text Reset -command simResetAll pack .cntl.quit .cntl.run .cntl.stop .cntl.step .cntl.reset -in .cntl -side left # Simulation speed control scale .spd -label {Simulator Speed (10*log Hz)} -from -10 -to 30 -length 10c \ -orient horizontal -command setSpeed pack .spd # Simulation mode set simMode forward frame .md ### Old Simulation mode stuff #pack .md #radiobutton .md.wedged -text Wedged -variable simMode \ # -value wedged -width 10 -command {setSimMode wedged} #radiobutton .md.stall -text Stall -variable simMode \ # -value stall -width 10 -command {setSimMode stall} #radiobutton .md.forward -text Forward -variable simMode \ # -value forward -width 10 -command {setSimMode forward} #pack .md.wedged .md.stall .md.forward -in .md -side left # simDelay defines number of milliseconds for each cycle of simulator # Initial value is 1000ms set simDelay 1000 # Set delay based on rate expressed in log(Hz) proc setSpeed {rate} { global simDelay set simDelay [expr round(1000 / pow(10,$rate/10.0))] } # Global variables controlling simulator execution # Should simulator be running now? set simGoOK 0 proc simStop {} { global simGoOK set simGoOK 0 } proc simStep {} { global simStat set simStat [simRun 1] } proc simGo {} { global simGoOK simDelay simStat set simGoOK 1 # Disable the Go and Step buttons # Enable the Stop button while {$simGoOK} { # run the simulator 1 cycle after $simDelay set simStat [simRun 1] if {$simStat != "AOK" && $simStat != "BUB"} {set simGoOK 0} update } # Disable the Stop button # Enable the Go and Step buttons } ############################################################################## # Pipe Register Display # ############################################################################## # Colors for Highlighting Data Sources set valaBg LightPink set valbBg PaleGreen1 # Overall width of pipe register display set pipeWidth 72 set pipeHeight 2 set labWidth 5 # Add labeled display to window proc addDisp {win width name} { global dpyFont labFont set lname [string tolower $name] frame $win.$lname pack $win.$lname -in $win -side left label $win.$lname.t -text $name -font $labFont label $win.$lname.n -width $width -font $dpyFont -bg lightgray -fg Black label $win.$lname.c -width $width -font $dpyFont -bg white -relief ridge pack $win.$lname.t $win.$lname.c $win.$lname.n -in $win.$lname -side top return [list $win.$lname.n $win.$lname.c] } # Set text in display row proc setDisp {wins txts} { for {set i 0} {$i < [llength $wins] && $i < [llength $txts]} {incr i} { set win [lindex $wins $i] set txt [lindex $txts $i] $win config -text $txt } } frame .p -width $pipeWidth pack .p -in . -side bottom label .p.lab -text "Pipeline Registers" -font $bigLabFont -height $sectionHeight pack .p.lab -in .p -side top label .p.mem -text "Memory Stage" -height $pipeHeight -width $pipeWidth -bg NavyBlue -fg White -font $bigLabFont label .p.ex -text "Execute Stage" -height $pipeHeight -width $pipeWidth -bg NavyBlue -fg White -font $bigLabFont label .p.id -text "Decode Stage" -height $pipeHeight -width $pipeWidth -bg NavyBlue -fg White -font $bigLabFont label .p.if -text "Fetch Stage" -height $pipeHeight -width $pipeWidth -bg NavyBlue -fg White -font $bigLabFont frame .p.mw frame .p.em frame .p.de frame .p.fd frame .p.pc frame .p.e pack .p.mw .p.mem .p.em .p.ex .p.e .p.de .p.id .p.fd .p.if .p.pc -in .p -side top -anchor w -expand 1 proc addLabel { win nstage cstage } { global labWidth labFont bigLabFont frame $win.lab label $win.name -text "$cstage" -width $labWidth -font $bigLabFont pack $win.name -in $win.lab -side left label $win.lab.t -text " " -font $labFont label $win.lab.n -width $labWidth -text "Input" -anchor w label $win.lab.c -width $labWidth -text "State" -anchor w pack $win.lab.t $win.lab.c $win.lab.n -in $win.lab -side top pack $win.lab -in $win -side left } addLabel .p.mw M W addLabel .p.em E M addLabel .p.de D E addLabel .p.fd F D addLabel .p.pc "" F proc addFill { win w } { frame $win.fill label $win.fill.t -text "" -width $w -bg lightgray label $win.fill.n -bg white -text "" -width $w -bg lightgray label $win.fill.c -bg white -text "" -width $w -bg lightgray pack $win.fill.c $win.fill.t $win.fill.n -in $win.fill -side top -expand 1 pack $win.fill -in $win -side right -expand 1 } addFill .p.mw 0 addFill .p.de 0 addFill .p.fd 0 addFill .p.pc 0 # Take list of lists, and transpose nesting # Assumes all lists are of same length proc ltranspose {inlist} { set result {} for {set i 0} {$i < [llength [lindex $inlist 0]]} {incr i} { set nlist {} for {set j 0} {$j < [llength $inlist]} {incr j} { set ele [lindex [lindex $inlist $j] $i] set nlist [concat $nlist [list $ele]] } set result [concat $result [list $nlist]] } return $result } # Fields in F display # Total size = 3+16 = 19 set pwins(F) [ltranspose [list [addDisp .p.pc 3 Stat] \ [addDisp .p.pc 16 predPC]]] # Fields in D display # Total size = 3+6+4+4+16+16 = 49 set pwins(D) [ltranspose \ [list [addDisp .p.fd 3 Stat] \ [addDisp .p.fd 6 Instr] \ [addDisp .p.fd 4 rA] \ [addDisp .p.fd 4 rB] \ [addDisp .p.fd 16 valC] \ [addDisp .p.fd 16 valP]]] # Fields in E Display # Total size = 3+6+16+16+16+4+4+4+4 = 73 set pwins(E) [ltranspose \ [list [addDisp .p.de 3 Stat] \ [addDisp .p.de 6 Instr] \ [addDisp .p.de 16 valC] \ [addDisp .p.de 16 valA] \ [addDisp .p.de 16 valB] \ [addDisp .p.de 4 dstE] \ [addDisp .p.de 4 dstM] \ [addDisp .p.de 4 srcA] \ [addDisp .p.de 4 srcB]]] # Fields in M Display # Total size = 3+6+3+16+16+4+4 = 52 set pwins(M) [ltranspose \ [list [addDisp .p.em 3 Stat] \ [addDisp .p.em 6 Instr] \ [addDisp .p.em 3 Cnd] \ [addDisp .p.em 16 valE] \ [addDisp .p.em 16 valA] \ [addDisp .p.em 4 dstE] \ [addDisp .p.em 4 dstM]]] # Fields in W display # Total size = 3+6+16+16+4+4 = 49 set pwins(W) [ltranspose \ [list [addDisp .p.mw 3 Stat] \ [addDisp .p.mw 6 Instr] \ [addDisp .p.mw 16 valE] \ [addDisp .p.mw 16 valM] \ [addDisp .p.mw 4 dstE] \ [addDisp .p.mw 4 dstM]]] # update status line for specified pipe register proc updateStage {name current txts} { set Name [string toupper $name] global pwins set wins [lindex $pwins($Name) $current] setDisp $wins $txts } # Create Array of windows corresponding to data sources set rwins(wm) .p.mw.valm.c set rwins(we) .p.mw.vale.c set rwins(me) .p.em.vale.c set rwins(ea) .p.de.vala.c set rwins(eb) .p.de.valb.c # Highlight Data Source Registers for valA, valB proc showSources { a b } { global rwins valaBg valbBg # Set them all to white foreach w [array names rwins] { $rwins($w) config -bg White } if {$a != "none"} { $rwins($a) config -bg $valaBg } if {$b != "none"} { $rwins($b) config -bg $valbBg } # Indicate forwarding destinations by their color .p.de.vala.t config -bg $valaBg .p.de.valb.t config -bg $valbBg } ########################################################################## # Instruction Display # ########################################################################## toplevel .c wm title .c "Program Code" frame .c.cntl pack .c.cntl -in .c -side top -anchor w label .c.filelab -width 10 -text "File" entry .c.filename -width 20 -relief sunken -textvariable codeFile \ -font $dpyFont -bg white button .c.loadbutton -width $cntlBW -command {loadCode $codeFile} -text Load pack .c.filelab .c.filename .c.loadbutton -in .c.cntl -side left proc clearCode {} { simLabel {} {} destroy .c.t destroy .c.tr } proc createCode {} { # Create Code Structure frame .c.t pack .c.t -in .c -side top -anchor w # Support up to 4 columns of code, each $codeRowCount lines long frame .c.tr pack .c.tr -in .c.t -side top -anchor nw } proc loadCode {file} { # Kill old code window clearCode # Create new one createCode simCode $file simResetAll } # Start with initial code window, even though it will be destroyed. createCode # Add a line of code to the display proc addCodeLine {line addr op text} { global codeRowCount # Create new line in display global codeFont frame .c.tr.$addr pack .c.tr.$addr -in .c.tr -side top -anchor w label .c.tr.$addr.a -width 6 -text [format "0x%x" $addr] -font $codeFont label .c.tr.$addr.i -width 20 -text $op -font $codeFont label .c.tr.$addr.s -width 2 -text "" -font $codeFont -bg white label .c.tr.$addr.t -text $text -font $codeFont pack .c.tr.$addr.a .c.tr.$addr.i .c.tr.$addr.s \ .c.tr.$addr.t -in .c.tr.$addr -side left } # Keep track of which instructions have stage labels set oldAddr {} proc simLabel {addrs labs} { global oldAddr set newAddr {} # Clear away any old labels foreach a $oldAddr { .c.tr.$a.s config -text "" } for {set i 0} {$i < [llength $addrs]} {incr i} { set a [lindex $addrs $i] set t [lindex $labs $i] if {[winfo exists .c.tr.$a]} { .c.tr.$a.s config -text $t set newAddr [concat $newAddr $a] } } set oldAddr $newAddr } proc simResetAll {} { global simStat set simStat "AOK" simReset clearMem simLabel {} {} } ############################################################################### # Memory Display # ############################################################################### toplevel .m wm title .m "Memory Contents" frame .m.t pack .m.t -in .m -side top -anchor w label .m.t.lab -width 6 -font $dpyFont -text " " pack .m.t.lab -in .m.t -side left for {set i 0} {$i < 16} {incr i 8} { label .m.t.a$i -width 16 -font $dpyFont -text [format " 0x---%x" [expr $i % 16]] pack .m.t.a$i -in .m.t -side left } # Keep track of range of addresses currently displayed set minAddr 0 set memCnt 0 set haveMem 0 proc createMem {nminAddr nmemCnt} { global minAddr memCnt haveMem codeFont dpyFont normalBg set minAddr $nminAddr set memCnt $nmemCnt if { $haveMem } { destroy .m.e } # Create Memory Structure frame .m.e set haveMem 1 pack .m.e -in .m -side top -anchor w # Now fill it with values for {set i 0} {$i < $memCnt} {incr i 16} { set addr [expr $minAddr + $i] frame .m.e.r$i pack .m.e.r$i -side bottom -in .m.e label .m.e.r$i.lab -width 6 -font $dpyFont -text [format "0x%.3x-" [expr $addr / 16]] pack .m.e.r$i.lab -in .m.e.r$i -side left for {set j 0} {$j < 16} {incr j 8} { set a [expr $addr + $j] label .m.e.v$a -width 16 -font $dpyFont -relief ridge \ -bg $normalBg pack .m.e.v$a -in .m.e.r$i -side left } } } proc setMem {Addr Val} { global minAddr memCnt if {$Addr < $minAddr || $Addr > [expr $minAddr + $memCnt]} { error "Memory address $Addr out of range" } .m.e.v$Addr config -text [format %16x $Val] } proc clearMem {} { destroy .m.e createMem 0 0 } ############################################################################### # Command Line Initialization # ############################################################################### # Get code file name from input # Find file with specified extension proc findFile {tlist ext} { foreach t $tlist { if {[string match "*.$ext" $t]} {return $t} } return "" } set codeFile [findFile $argv yo] if {$codeFile != ""} { loadCode $codeFile}

sim/pipe/pipeline.h

/****************************************************************************** * pipe.h * * Code for implementing pipelined processor simulators ******************************************************************************/ #ifndef PIPE_H #define PIPE_H /****************************************************************************** * #includes ******************************************************************************/ #include <stdio.h> /****************************************************************************** * typedefs ******************************************************************************/ /* Different control operations for pipeline register */ /* LOAD: Copy next state to current */ /* STALL: Keep current state unchanged */ /* BUBBLE: Set current state to nop */ /* ERROR: Occurs when both stall & load signals set */ typedef enum { P_LOAD, P_STALL, P_BUBBLE, P_ERROR } p_stat_t; typedef struct { /* Current and next register state */ void *current; void *next; /* Contents of register when bubble occurs */ void *bubble_val; /* Number of state bytes */ int count; /* How should state be updated next time? */ p_stat_t op; } pipe_ele, *pipe_ptr; /****************************************************************************** * function declarations ******************************************************************************/ /* Create new pipe with count bytes of state */ /* bubble_val indicates state corresponding to pipeline bubble */ pipe_ptr new_pipe(int count, void *bubble_val); /* Update all pipes */ void update_pipes(); /* Set all pipes to bubble values */ void clear_pipes(); /* Utility code */ /* Print hex/oct/binary format with leading zeros */ /* bpd denotes bits per digit Should be in range 1-4, bpw denotes bits per word.*/ void wprint(uword_t x, int bpd, int bpw, FILE *fp); void wstring(uword_t x, int bpd, int bpw, char *s); /******************************************************************************/ #endif /* PIPE_H */

sim/pipe/sim.h

/********** Typedefs ************/ /* EX stage mux settings */ typedef enum { MUX_NONE, MUX_EX_A, MUX_EX_B, MUX_MEM_E, MUX_WB_M, MUX_WB_E } mux_source_t; /* Simulator operating modes */ typedef enum { S_WEDGED, S_STALL, S_FORWARD } sim_mode_t; /* Pipeline stage identifiers for stage operation control */ typedef enum { IF_STAGE, ID_STAGE, EX_STAGE, MEM_STAGE, WB_STAGE } stage_id_t; /********** Defines **************/ /* Get ra out of one byte regid field */ #define GET_RA(r) HI4(r) /* Get rb out of one byte regid field */ #define GET_RB(r) LO4(r) /************ Global state declaration ****************/ /* How many cycles have been simulated? */ extern word_t cycles; /* How many instructions have passed through the EX stage? */ extern word_t instructions; /* Both instruction and data memory */ extern mem_t mem; /* Keep track of range of addresses that have been written */ extern word_t minAddr; extern word_t memCnt; /* Register file */ extern mem_t reg; /* Condition code register */ extern cc_t cc; extern stat_t stat; /* Operand sources in EX (to show forwarding) */ extern mux_source_t amux, bmux; /* Provide global access to current states of all pipeline registers */ pipe_ptr pc_state, if_id_state, id_ex_state, ex_mem_state, mem_wb_state; /* Current States */ extern pc_ptr pc_curr; extern if_id_ptr if_id_curr; extern id_ex_ptr id_ex_curr; extern ex_mem_ptr ex_mem_curr; extern mem_wb_ptr mem_wb_curr; /* Next States */ extern pc_ptr pc_next; extern if_id_ptr if_id_next; extern id_ex_ptr id_ex_next; extern ex_mem_ptr ex_mem_next; extern mem_wb_ptr mem_wb_next; /* Pending updates to state */ extern word_t cc_in; extern word_t wb_destE; extern word_t wb_valE; extern word_t wb_destM; extern word_t wb_valM; extern word_t mem_addr; extern word_t mem_data; extern bool_t mem_write; /* Intermdiate stage values that must be used by control functions */ extern word_t f_pc; extern byte_t imem_icode; extern byte_t imem_ifun; extern bool_t imem_error; extern bool_t instr_valid; extern word_t d_regvala; extern word_t d_regvalb; extern word_t e_vala; extern word_t e_valb; extern bool_t e_bcond; extern bool_t dmem_error; /* Simulator operating mode */ extern sim_mode_t sim_mode; /* Log file */ extern FILE *dumpfile; /*************** Simulation Control Functions ***********/ /* Bubble next execution of specified stage */ void sim_bubble_stage(stage_id_t stage); /* Stall stage (has effect at next update) */ void sim_stall_stage(stage_id_t stage); /* Sets the simulator name (called from main routine in HCL file) */ void set_simname(char *name); /* Initialize simulator */ void sim_init(); /* Reset simulator state, including register, instruction, and data memories */ void sim_reset(); /* Run pipeline until one of following occurs: - A status error is encountered in WB. - max_instr instructions have completed through WB - max_cycle cycles have been simulated Return number of instructions executed. if statusp nonnull, then will be set to status of final instruction if ccp nonnull, then will be set to condition codes of final instruction */ word_t sim_run_pipe(word_t max_instr, word_t max_cycle, byte_t *statusp, cc_t *ccp); /* If dumpfile set nonNULL, lots of status info printed out */ void sim_set_dumpfile(FILE *file); /* * sim_log dumps a formatted string to the dumpfile, if it exists * accepts variable argument list */ void sim_log( const char *format, ... ); /******************* GUI Interface Functions **********************/ #ifdef HAS_GUI void signal_sources(); void signal_register_clear(); void report_pc(unsigned fpc, unsigned char fpcv, unsigned dpc, unsigned char dpcv, unsigned epc, unsigned char epcv, unsigned mpc, unsigned char mpcv, unsigned wpc, unsigned char wpcv); void report_state(char *id, word_t current, char *txt); void show_cc(cc_t cc); void show_cpi(); void show_stat(stat_t stat); void create_memory_display(); void set_memory(word_t addr, word_t val); #endif

sim/pipe/stages.h

/* * stages.h - Defines the layout of the pipe registers * Declares the functions that implement the pipeline stages */ /********** Pipeline register contents **************/ /* Program Counter */ typedef struct { word_t pc; stat_t status; } pc_ele, *pc_ptr; /* IF/ID Pipe Register */ typedef struct { byte_t icode; /* Single byte instruction code */ byte_t ifun; /* ALU/JMP qualifier */ byte_t ra; /* Register ra ID */ byte_t rb; /* Register rb ID */ word_t valc; /* Instruction word encoding immediate data */ word_t valp; /* Incremented program counter */ stat_t status; /* The following is included for debugging */ word_t stage_pc; } if_id_ele, *if_id_ptr; /* ID/EX Pipe Register */ typedef struct { byte_t icode; /* Instruction code */ byte_t ifun; /* ALU/JMP qualifier */ word_t valc; /* Immediate data */ word_t vala; /* valA */ word_t valb; /* valB */ byte_t srca; /* Source Reg ID for valA */ byte_t srcb; /* Source Reg ID for valB */ byte_t deste; /* Destination register for valE */ byte_t destm; /* Destination register for valM */ stat_t status; /* The following is included for debugging */ word_t stage_pc; } id_ex_ele, *id_ex_ptr; /* EX/MEM Pipe Register */ typedef struct { byte_t icode; /* Instruction code */ byte_t ifun; /* ALU/JMP qualifier */ bool_t takebranch; /* Taken branch signal */ word_t vale; /* valE */ word_t vala; /* valA */ byte_t deste; /* Destination register for valE */ byte_t destm; /* Destination register for valM */ byte_t srca; /* Source register for valA */ stat_t status; /* The following is included for debugging */ word_t stage_pc; } ex_mem_ele, *ex_mem_ptr; /* Mem/WB Pipe Register */ typedef struct { byte_t icode; /* Instruction code */ byte_t ifun; /* ALU/JMP qualifier */ word_t vale; /* valE */ word_t valm; /* valM */ byte_t deste; /* Destination register for valE */ byte_t destm; /* Destination register for valM */ stat_t status; /* The following is included for debugging */ word_t stage_pc; } mem_wb_ele, *mem_wb_ptr; /************ Global Declarations ********************/ extern pc_ele bubble_pc; extern if_id_ele bubble_if_id; extern id_ex_ele bubble_id_ex; extern ex_mem_ele bubble_ex_mem; extern mem_wb_ele bubble_mem_wb; /************ Function declarations *******************/ /* Stage functions */ void do_if_stage(); void do_id_wb_stages(); /* Both ID and WB */ void do_ex_stage(); void do_mem_stage(); /* Set stalling conditions for different stages */ void do_stall_check();

sim/pipe/Makefile

# Modify this line to indicate the default version to build VERSION=std # Comment this out if you don't have Tcl/Tk on your system GUIMODE=-DHAS_GUI # Modify the following line so that gcc can find the libtcl.so and # libtk.so libraries on your system. You may need to use the -L option # to tell gcc which directory to look in. Comment this out if you # don't have Tcl/Tk. TKLIBS=-L/usr/lib -ltk -ltcl # Modify the following line so that gcc can find the tcl.h and tk.h # header files on your system. Comment this out if you don't have # Tcl/Tk. TKINC=-isystem /usr/include/tcl8.5 # Modify these two lines to choose your compiler and compile time # flags. CC=gcc CFLAGS=-Wall -O2 ################################################## # You shouldn't need to modify anything below here ################################################## MISCDIR=../misc HCL2C=$(MISCDIR)/hcl2c INC=$(TKINC) -I$(MISCDIR) $(GUIMODE) LIBS=$(TKLIBS) -lm YAS = ../misc/yas all: psim drivers # This rule builds the PIPE simulator psim: psim.c sim.h pipe-$(VERSION).hcl $(MISCDIR)/isa.c $(MISCDIR)/isa.h # Building the pipe-$(VERSION).hcl version of PIPE $(HCL2C) -n pipe-$(VERSION).hcl < pipe-$(VERSION).hcl > pipe-$(VERSION).c $(CC) $(CFLAGS) $(INC) -o psim psim.c pipe-$(VERSION).c \ $(MISCDIR)/isa.c $(LIBS) # This rule builds driver programs for Part C of the Architecture Lab drivers: ./gen-driver.pl -n 4 -f ncopy.ys > sdriver.ys ../misc/yas sdriver.ys ./gen-driver.pl -n 63 -f ncopy.ys > ldriver.ys ../misc/yas ldriver.ys # These are implicit rules for assembling .yo files from .ys files. .SUFFIXES: .ys .yo .ys.yo: $(YAS) $*.ys clean: rm -f psim pipe-*.c *.o *.exe *~

sim/pipe/README

/*********************************************************************** * Pipelined Y86-64 Simulator * * Copyright (c) 2002, 2010, 2015 R. Bryant and D. O'Hallaron, * All rights reserved. * May not be used, modified, or copied without permission. ***********************************************************************/ This directory contains the code to construct simulators for PIPE and the variants of it described in the homework exercises. ************************* 1. Building the simulator ************************* Different versions of the PIPE simulator can be constructed to use different HCL files when working on the different homework problems. Binary VERSION HCL File Description psim std pipe-std.hcl Standard simulator (default) psim broken pipe-broken.hcl Does not handle any hazards psim full pipe-full.hcl For adding iaddq psim nobypass pipe-nobypass.hcl For implementing PIPE- (called pipe-stall.hcl in text) psim lf pipe-lf.hcl For implementing load forwarding psim nt pipe-nt.hcl For implementing NT branch prediction psim btfnt pipe-btfnt.hcl For implementing BTFNT branch pred. psim 1w pipe-1w.hcl For implementing single write port psim super pipe-super.hcl Implements iaddq & load forwarding The Makefile can be configured to build simulators that support GUI and/or TTY interfaces. A simulator running in TTY mode prints all information about its runtime behavior on the terminal. It's hard to understand what's going on, but useful for automated testing, and doesn't require any special installation features. A simulator running in GUI mode uses a fancy graphical user interface. Nice for visualizing and debugging, but requires installation of Tcl/Tk on your system. The Makefile has simple instructions for building the TTY and GUI forms. In either case, once you've configured the Makefile, you can build different versions of the simulators with different HCL files with commands of the form: unix> make clean; make psim VERSION=xxx where "xxx" is one of the versions listed above. To save typing, you can set the Makefile's VERSION variable. For example, if you are working on Problems 4.52 and 4.53, which require to modify pipe-full.hcl, then you could set VERSION=full in the Makefile. Typing unix> make clean; make psim would then make the pipe-full.hcl version of PIPE. *********************** 2. Using the simulators *********************** The simulator recognizes the following command line arguments: Usage: psim [-htg] [-l m] [-v n] file.yo file.yo required in GUI mode, optional in TTY mode (default stdin) -h Print this message -g Run in GUI mode instead of TTY mode (default TTY mode) -l m Set instruction limit to m [TTY mode only] (default 10000) -v n Set verbosity level to 0 <= n <= 2 [TTY mode only] (default 2) -t Test result against the ISA simulator (yis) [TTY model only] ******** 3. Files ******** Makefile Build the simulator Makefile-sim Makefile for the student distribution README This file ********************************************** * Files related to the CS:APP Architecture Lab ********************************************** * Sample programs ncopy.ys The default version of ncopy that the students optimize ncopy.c C version of ncopy that defines its semantics * Preconstructed driver programs (by gen-driver.pl) sdriver.ys Driver that calls ncopy.ys on a short (4-word) array ldriver.ys Driver that calls ncopy.ys on a longer (63-word) array Both drivers are generated automatically by the Makefile by typing "make drivers". * Solution files (Instructors only) gen-ncopy.pl Generates versions of benchmark program with various optimizations. See comments in file for explanation. * Testing scripts gen-driver.pl Generate a driver program for an arbitrary ncopy implementation (default ncopy.ys). Type "make drivers" to construct sdriver.ys and ldriver.ys. benchmark.pl Runs an implementation of ncopy on array sizes 1 to 64 (default ncopy.ys) and computes its performance in units of CPE (cycles per element). correctness.pl Runs an implementation of ncopy on array sizes 0 to 64, and several longer ones and checks each for correctness. check-len.pl Determines number of bytes in .yo representation of ncopy function. **************************************************** * HCL files for different versions of the simulators **************************************************** pipe-std.hcl The standard PIPE processor described in the text pipe-broken.hcl A simulator that does not detect or handle hazards (useful when explaining hazards in lectures) * HCL files for various CS:APP Homework Problems pipe-nobypass.hcl 4.51: Build version of PIPE without bypassing (called pipe-stall.hcl in the text) pipe-full.hcl 4.52-53: Add iaddq instruction to PIPE pipe-nt.hcl 4.54: Implement branch not taken strategy pipe-btfnt.hcl 4.55: Implement back-taken forward-not-taken strategy pipe-lf.hcl 4.56: Implement load forwarding logic pipe-1w.hcl 4.57: Implement single ported register file * HCL solution files for the CS:APP Homework Problems (Instructors only) pipe-nobypass-ans.hcl 4.51 solution pipe-full-ans.hcl 4.52-53 solutions pipe-nt-ans.hcl 4.54 solution pipe-btfnt-ans.hcl 4.55 solution pipe-lf-ans.hcl 4.56 solutions pipe-1w-ans.hcl 4.57 solutions pipe-super.hcl Gives best performance for lab ***************************** * PIPE simulator source files ***************************** psim.c Base simulator code sim.h PIPE header files pipeline.h stages.h pipe.tcl TCL script for the GUI version of PIPE

sim/pipe/ncopy.c

#include <stdio.h> typedef word_t word_t; word_t src[8], dst[8]; /* $begin ncopy */ /* * ncopy - copy src to dst, returning number of positive ints * contained in src array. */ word_t ncopy(word_t *src, word_t *dst, word_t len) { word_t count = 0; word_t val; while (len > 0) { val = *src++; *dst++ = val; if (val > 0) count++; len--; } return count; } /* $end ncopy */ int main() { word_t i, count; for (i=0; i<8; i++) src[i]= i+1; count = ncopy(src, dst, 8); printf ("count=%d\n", count); exit(0); }

sim/pipe/ncopy.ys

#/* $begin ncopy-ys */ ################################################################## # ncopy.ys - Copy a src block of len words to dst. # Return the number of positive words (>0) contained in src. # # Include your name and ID here. # # Describe how and why you modified the baseline code. # ################################################################## # Do not modify this portion # Function prologue. # %rdi = src, %rsi = dst, %rdx = len ncopy: ################################################################## # You can modify this portion # Loop header xorq %rax,%rax # count = 0; andq %rdx,%rdx # len <= 0? jle Done # if so, goto Done: Loop: mrmovq (%rdi), %r10 # read val from src... rmmovq %r10, (%rsi) # ...and store it to dst andq %r10, %r10 # val <= 0? jle Npos # if so, goto Npos: irmovq $1, %r10 addq %r10, %rax # count++ Npos: irmovq $1, %r10 subq %r10, %rdx # len-- irmovq $8, %r10 addq %r10, %rdi # src++ addq %r10, %rsi # dst++ andq %rdx,%rdx # len > 0? jg Loop # if so, goto Loop: ################################################################## # Do not modify the following section of code # Function epilogue. Done: ret ################################################################## # Keep the following label at the end of your function End: #/* $end ncopy-ys */

sim/pipe/benchmark.pl

#!/usr/bin/perl #!/usr/local/bin/perl # # benchmark.pl - Run test of pipeline on ncopy for different block sizes # and determine CPE (cycles per element) # use Getopt::Std; # # Configuration # $blocklen = 64; $yas = "../misc/yas"; $pipe = "./psim"; $gendriver = "./gen-driver.pl"; $fname = "bdriver"; $verbose = 1; ## Grading criteria $totalpoints = 60; # What CPE is required to get full credit? $fullcpe = 7.5; # What CPE is required to get nonzero credit: $threshcpe = 10.5; # # usage - Print the help message and terminate # sub usage { print STDERR "Usage: $0 [-hq] [-n N] -f FILE\n"; print STDERR " -h Print help message\n"; print STDERR " -q Quiet mode (default verbose)\n"; print STDERR " -n N Set max number of elements up to 64 (default $blocklen)\n"; print STDERR " -f FILE Input .ys file is FILE\n"; die "\n"; } getopts('hqn:f:'); if ($opt_h) { usage(); } if ($opt_q) { $verbose = 0; } if ($opt_n) { $blocklen = $opt_n; if ($blocklen < 0 || $blocklen > 64) { print STDERR "n must be between 0 and 64\n"; die "\n"; } } # Filename is required if (!$opt_f) { $ncopy = "ncopy"; } else { $ncopy = $opt_f; # Strip off .ys $ncopy =~ s/\.ys//; } if ($verbose) { print "\t$ncopy\n"; } $tcpe = 0; for ($i = 0; $i <= $blocklen; $i++) { !(system "$gendriver -n $i -f $ncopy.ys > $fname$i.ys") || die "Couldn't generate driver file $fname$i.ys\n"; !(system "$yas $fname$i.ys") || die "Couldn't assemble file $fname$i.ys\n"; $stat = `$pipe -v 0 $fname$i.yo` || die "Couldn't simulate file $fname$i.yo\n"; !(system "rm $fname$i.ys $fname$i.yo") || die "Couldn't remove files $fname$i.ys and/or $fname$i.yo\n"; chomp $stat; $stat =~ s/[ ]*CPI:[ ]*//; $stat =~ s/ cycles.*//; if ($i > 0) { $cpe = $stat/$i; if ($verbose) { printf "%d\t%d\t%.2f\n", $i, $stat, $cpe; } $tcpe += $cpe; } else { if ($verbose) { printf "%d\t%d\n", $i, $stat; } } } $acpe = $tcpe/$blocklen; printf "Average CPE\t%.2f\n", $acpe; ## Compute Score $score = 0; if ($acpe <= $fullcpe) { $score = $totalpoints; } elsif ($acpe <= $threshcpe) { $score = $totalpoints * ($threshcpe - $acpe)/($threshcpe - $fullcpe); } printf "Score\t%.1f/%.1f\n", $score, $totalpoints;

sim/pipe/correctness.pl

#!/usr/bin/perl #!/usr/local/bin/perl # # correctness.pl - Test ncopy assembly code for correctness # use Getopt::Std; # # Configuration # $blocklen = 64; $over = 3; $yas = "../misc/yas"; $yis = "../misc/yis"; $pipe = "./psim"; $gendriver = "./gen-driver.pl"; $fname = "cdriver"; $verbose = 1; # Maximum allowable code length $bytelim = 1000; # # usage - Print the help message and terminate # sub usage { print STDERR "Usage: $0 [-hqp] [-n N] -f FILE\n"; print STDERR " -h Print help message\n"; print STDERR " -q Quiet mode (default verbose)\n"; print STDERR " -p Run program on pipeline simulator (default ISA sim)\n"; print STDERR " -n N Set max number of elements up to 64 (default $blocklen)\n"; print STDERR " -f FILE Input .ys file is FILE\n"; print STDERR " -b blim set byte limit for function\n"; die "\n"; } getopts('hqpn:f:b:'); if ($opt_h) { usage(); } if ($opt_q) { $verbose = 0; } if ($opt_b) { $bytelim = $opt_b; } $usepipe = 0; if ($opt_p) { $usepipe = 1; print "Simulating with pipeline simulator psim\n"; } else { print "Simulating with instruction set simulator yis\n"; } if ($opt_n) { $blocklen = $opt_n; if ($blocklen < 0) { print STDERR "n must be >= 0\n"; die "\n"; } } # Filename is required if (!$opt_f) { $ncopy = "ncopy"; } else { $ncopy = $opt_f; # Strip off .ys $ncopy =~ s/\.ys//; } if ($verbose) { print "\t$ncopy\n"; } $goodcnt = 0; for ($i = 0; $i <= $blocklen+$over; $i++) { $len = $i; if ($i > $blocklen) { # Try some larger values $len = $blocklen * ($i - $blocklen + 1); } !(system "$gendriver -rc -n $len -f $ncopy.ys -b $bytelim > $fname$len.ys") || die "Couldn't generate driver file $fname$len.ys\n"; !(system "$yas $fname$len.ys") || die "Couldn't assemble file $fname$len.ys\n"; if ($usepipe) { !(system "$pipe -v 1 $fname$len.yo > $fname$len.pipe") || die "Couldn't simulate file $fname$len.yo with pipeline simulator\n"; $stat = `grep "rax:" $fname$len.pipe`; !(system "rm $fname$len.ys $fname$len.yo $fname$len.pipe") || die "Couldn't remove files $fname$len.ys and/or $fname$len.yo and/or $fname$len.pipe\n"; chomp $stat; } else { !(system "$yis $fname$len.yo > $fname$len.yis") || die "Couldn't simulate file $fname$len.yo with instruction set simulator\n"; $stat = `grep rax $fname$len.yis`; !(system "rm $fname$len.ys $fname$len.yo $fname$len.yis") || die "Couldn't remove files $fname$len.ys and/or $fname$len.yo and/or $fname$len.yis\n"; chomp $stat; } $result = "failed"; if ($stat =~ "zzzz") { $result = "Couldn't run checking code"; } if ($stat =~ "aaaa") { $result = "OK"; $goodcnt ++; } if ($stat =~ "bbbb") { $result = "Bad count"; } if ($stat =~ "cccc") { $result = "Program too long"; printf "%d\t%s\n", $len, $result; last; } if ($stat =~ "dddd") { $result = "Incorrect copying"; } if ($stat =~ "eeee") { $result = "Corruption before or after destination"; } if ($verbose) { printf "%d\t%s\n", $len, $result; } } $bp1 = $blocklen+$over+1; printf "$goodcnt/$bp1 pass correctness test\n";

sim/pipe/gen-driver.pl

#!/usr/bin/perl #!/usr/local/bin/perl # # gen-driver - Generate driver file for any ncopy function # use Getopt::Std; $n = 0; getopts('hcrn:f:b:'); if ($opt_h) { print STDERR "Usage $argv[0] [-h] [-c] [-n N] [-f FILE]\n"; print STDERR " -h print help message\n"; print STDERR " -c include correctness checking code\n"; print STDERR " -n N set number of elements\n"; print STDERR " -f FILE set input file (default stdin)\n"; print STDERR " -b blim set byte limit for function\n"; print STDERR " -r Allow random result\n"; die "\n"; } $check = 0; if ($opt_c) { $check = 1; } $bytelim = 1000; if ($opt_b) { $bytelim = $opt_b; } if ($opt_n) { $n = $opt_n; if ($n < 0) { print STDERR "n must be at least 0\n"; die "\n"; } } $randomval = 0; # Accumulated count $rval = 0; if ($opt_r) { $randomval = 1; } else { # Value that should be returned by function $tval = int($n/2); } # The data to be stored. @data = (); for ($i = 0; $i < $n; $i++) { $data[$i] = -($i+1); if ($randomval) { if (int(rand(2)) == 1) { $data[$i] = -$data[$i]; $rval++; } } else { if ($rval < $tval && int(rand(2)) % 2 == 1 || $tval - $rval >= $n - $i) { $data[$i] = -$data[$i]; $rval++; } } } # Values to put at beginning and end of destination $Preval = "0xbcdefa"; $Postval = "0xdefabc"; print <<PROLOGUE; ####################################################################### # Test for copying block of size $n; ####################################################################### .pos 0 main: irmovq Stack, %rsp # Set up stack pointer # Set up arguments for copy function and then invoke it irmovq \$$n, %rdx # src and dst have $n elements irmovq dest, %rsi # dst array irmovq src, %rdi # src array call ncopy PROLOGUE if ($check) { print <<CALL; call check # Call checker code halt # should halt with 0xaaaa in %rax CALL } else { print <<HALT; halt # should halt with num nonzeros in %rax HALT } print "StartFun:\n"; if ($opt_f) { open (CODEFILE, "$opt_f") || die "Can't open code file $opt_f\n"; while (<CODEFILE>) { printf "%s", $_; } } else { while (<>) { printf "%s", $_; } } print "EndFun:\n"; if ($check) { print <<CHECK; #################################################################### # Epilogue code for the correctness testing driver #################################################################### # This is the correctness checking code. # It checks: # 1. %rax has $rval. Set %rax to 0xbbbb if not. # 2. The total length of the code is less than or equal to $bytelim. # Set %rax to 0xcccc if not. # 3. The source data was copied to the destination. # Set %rax to 0xdddd if not. # 4. The words just before and just after the destination region # were not corrupted. Set %rax to 0xeeee if not. # If all checks pass, then sets %rax to 0xaaaa check: # Return value test irmovq \$$rval,%r10 subq %r10,%rax je checkb irmovq \$0xbbbb,%rax # Failed test #1 jmp cdone checkb: # Code length check irmovq EndFun,%rax irmovq StartFun,%rdx subq %rdx,%rax irmovq \$$bytelim,%rdx subq %rax,%rdx jge checkm irmovq \$0xcccc,%rax # Failed test #2 jmp cdone checkm: irmovq dest, %rdx # Pointer to next destination location irmovq src,%rbx # Pointer to next source location irmovq \$$n,%rdi # Count andq %rdi,%rdi je checkpre # Skip check if count = 0 mcloop: mrmovq (%rdx),%rax mrmovq (%rbx),%rsi subq %rsi,%rax je mok irmovq \$0xdddd,%rax # Failed test #3 jmp cdone mok: irmovq \$8,%rax addq %rax,%rdx # dest ++ addq %rax,%rbx # src++ irmovq \$1,%rax subq %rax,%rdi # cnt-- jg mcloop checkpre: # Check for corruption irmovq Predest,%rdx mrmovq (%rdx), %rax # Get word before destination irmovq \$$Preval, %rdx subq %rdx,%rax je checkpost irmovq \$0xeeee,%rax # Failed test #4 jmp cdone checkpost: # Check for corruption irmovq Postdest,%rdx mrmovq (%rdx), %rax # Get word after destination irmovq \$$Postval, %rdx subq %rdx,%rax je checkok irmovq \$0xeeee,%rax # Failed test #4 jmp cdone checkok: # Successful checks irmovq \$0xaaaa,%rax cdone: ret CHECK } print <<EPILOGUE1; ############################### # Source and destination blocks ############################### .align 8 src: EPILOGUE1 for ($i = 0; $i < $n; $i++) { print "\t.quad $data[$i]\n"; } print <<EPILOGUE2; .quad $Preval # This shouldn't get moved .align 16 Predest: .quad $Preval dest: EPILOGUE2 for ($i = 0; $i < $n; $i++) { print "\t.quad 0xcdefab\n"; } print <<EPILOGUE3; Postdest: .quad $Postval .align 8 # Run time stack .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 .quad 0 Stack: EPILOGUE3

sim/pipe/check-len.pl

#!/usr/bin/perl # Check length of ncopy function in .yo file # Assumes that function starts with label "ncopy:" # and finishes with label "End:" $startpos = -1; $endpos = -1; while (<>) { $line = $_; if ($line =~ /(0x[0-9a-fA-F]+):.* ncopy:/) { $startpos = hex($1); } if ($line =~ /(0x[0-9a-fA-F]+):.* End:/) { $endpos = hex($1); } } if ($startpos >= 0 && $endpos > $startpos) { $len = $endpos - $startpos; print "ncopy length = $len bytes\n"; } else { print "Couldn't determine ncopy length\n"; }

sim/y86-code/abs-asum-cmov.ys

# Modification of asum code to compute absolute values of entries. # This version uses a conditional move # Execution begins at address 0 .pos 0 irmovq stack, %rsp # Set up stack pointer call main # Execute main program halt # Terminate program # Array of 4 elements .align 8 array: .quad 0x0000000d000d000d .quad 0xffffff3fff3fff40 # -0x000000c000c000c0 .quad 0x00000b000b000b00 .quad 0xffff5fff5fff6000 # -0x0000a000a000a000 main: irmovq array,%rdi irmovq $4,%rsi call absSum # absSum(array, 4) ret # long absSum(long *start, long count) # start in %rdi, count in %rsi absSum: irmovq $8,%r8 # Constant 8 irmovq $1,%r9 # Constant 1 xorq %rax,%rax # sum = 0 andq %rsi,%rsi # Set condition codes jmp test /* $begin abs-sum-cmov-ys */ loop: mrmovq (%rdi),%r10 # x = *start xorq %r11,%r11 # Constant 0 subq %r10,%r11 # -x cmovg %r11,%r10 # If -x > 0 then x = -x addq %r10,%rax # Add to sum addq %r8,%rdi # start++ subq %r9,%rsi # count-- test: jne loop # Stop when 0 /* $end abs-sum-cmov-ys */ ret # The stack starts here and grows to lower addresses .pos 0x200 stack:

sim/y86-code/abs-asum-jmp.ys

# Modification of asum code to compute absolute values of entries. # This version uses a conditional jump # Execution begins at address 0 .pos 0 irmovq stack, %rsp # Set up stack pointer call main # Execute main program halt # Terminate program # Array of 4 elements .align 8 array: .quad 0x0000000d000d000d .quad 0xffffff3fff3fff40 # -0x000000c000c000c0 .quad 0x00000b000b000b00 .quad 0xffff5fff5fff6000 # -0x0000a000a000a000 main: irmovq array,%rdi irmovq $4,%rsi call absSum # absSum(array, 4) ret /* $begin abs-sum-jmp-ys */ # long absSum(long *start, long count) # start in %rdi, count in %rsi absSum: irmovq $8,%r8 # Constant 8 irmovq $1,%r9 # Constant 1 xorq %rax,%rax # sum = 0 andq %rsi,%rsi # Set condition codes jmp test loop: mrmovq (%rdi),%r10 # x = *start xorq %r11,%r11 # Constant 0 subq %r10,%r11 # -x jle pos # Skip if -x <= 0 rrmovq %r11,%r10 # x = -x pos: addq %r10,%rax # Add to sum addq %r8,%rdi # start++ subq %r9,%rsi # count-- test: jne loop # Stop when 0 ret /* $end abs-sum-jmp-ys */ # The stack starts here and grows to lower addresses .pos 0x200 stack:

sim/y86-code/asum.ys

# Execution begins at address 0 .pos 0 irmovq stack, %rsp # Set up stack pointer call main # Execute main program halt # Terminate program # Array of 4 elements .align 8 array: .quad 0x000d000d000d .quad 0x00c000c000c0 .quad 0x0b000b000b00 .quad 0xa000a000a000 main: irmovq array,%rdi irmovq $4,%rsi call sum # sum(array, 4) ret # long sum(long *start, long count) # start in %rdi, count in %rsi sum: irmovq $8,%r8 # Constant 8 irmovq $1,%r9 # Constant 1 xorq %rax,%rax # sum = 0 andq %rsi,%rsi # Set CC jmp test # Goto test loop: mrmovq (%rdi),%r10 # Get *start addq %r10,%rax # Add to sum addq %r8,%rdi # start++ subq %r9,%rsi # count--. Set CC test: jne loop # Stop when 0 ret # Return # Stack starts here and grows to lower addresses .pos 0x200 stack:

sim/y86-code/asumr.ys

# Execution begins at address 0 .pos 0 irmovq stack, %rsp # Set up stack pointer call main # Execute main program halt # Terminate program # Array of 4 elements .align 8 array: .quad 0x000d000d000d .quad 0x00c000c000c0 .quad 0x0b000b000b00 .quad 0xa000a000a000 main: irmovq array,%rdi irmovq $4,%rsi call rsum # rsum(array, 4) ret /* $begin rsum-ys */ # long rsum(long *start, long count) # start in %rdi, count in %rsi rsum: xorq %rax,%rax # Set return value to 0 andq %rsi,%rsi # Set condition codes jle return # If count <= 0, return 0 pushq %rbx # Save callee-saved register mrmovq (%rdi),%rbx # Get *start irmovq $-1,%r10 addq %r10,%rsi # count-- irmovq $8,%r10 addq %r10,%rdi # start++ call rsum addq %rbx,%rax # Add *start to sum popq %rbx # Restore callee-saved register return: ret /* $end rsum-ys */ # The stack starts here and grows to lower addresses .pos 0x200 stack:

sim/y86-code/asumi.ys

# Execution begins at address 0 .pos 0 irmovq stack, %rsp # Set up stack pointer call main # Execute main program halt # Terminate program # Array of 4 elements .align 8 array: .quad 0x000d000d000d .quad 0x00c000c000c0 .quad 0x0b000b000b00 .quad 0xa000a000a000 main: irmovq array,%rdi irmovq $4,%rsi call sum # sum(array, 4) ret /* $begin sumi-ys */ # long sum(long *start, long count) # start in %rdi, count in %rsi sum: xorq %rax,%rax # sum = 0 andq %rsi,%rsi # Set condition codes jmp test loop: mrmovq (%rdi),%r10 # Get *start addq %r10,%rax # Add to sum iaddq $8,%rdi # start++ iaddq $-1,%rsi # count-- test: jne loop # Stop when 0 ret /* $end sumi-ys */ # The stack starts here and grows to lower addresses .pos 0x100 stack:

sim/y86-code/cjr.ys

# /* $begin cjr-ys */ # Code to generate a combination of not-taken branch and ret irmovq Stack, %rsp irmovq rtnp,%rax pushq %rax # Set up return pointer xorq %rax,%rax # Set Z condition code jne target # Not taken (First part of combination) irmovq $1,%rax # Should execute this halt target: ret # Second part of combination irmovq $2,%rbx # Should not execute this halt rtnp: irmovq $3,%rdx # Should not execute this halt .pos 0x40 Stack: # /* $end cjr-ys */

sim/y86-code/j-cc.ys

irmovq $1, %rsi irmovq $2, %rdi irmovq $4, %rbp irmovq $-32, %rax irmovq $64, %rdx subq %rdx,%rax je target nop halt target: addq %rsi,%rdx nop nop nop halt

sim/y86-code/poptest.ys

# Test of Pop semantics for Y86-64 irmovq $0x100,%rsp # Initialize stack pointer irmovq $0xABCD,%rax pushq %rax # Put known value on stack popq %rsp # Either get 0xABCD, or 0xfc halt

sim/y86-code/pushquestion.ys

# Assembly Code to test semantics of pushq irmovq 0x100, %rsp pushq %rsp # Ambiguous popq %rax halt

sim/y86-code/pushtest.ys

# Test of Push semantics for Y86-64 irmovq $0x100,%rsp # Initialize stack pointer rrmovq %rsp,%rax # Save stack pointer pushq %rsp # Push the stack pointer (old or new?) popq %rdx # Get it back subq %rdx,%rax # Compute difference. Either 0 (old) or 4 (new). halt

sim/y86-code/prog1.ys

# prog1: Pad with 3 nop's irmovq $10,%rdx irmovq $3,%rax nop nop nop addq %rdx,%rax halt

sim/y86-code/prog2.ys

# prog2: Pad with 2 nop's irmovq $10,%rdx irmovq $3,%rax nop nop addq %rdx,%rax halt

sim/y86-code/prog3.ys

# prog3: Pad with 1 nop irmovq $10,%rdx irmovq $3,%rax nop addq %rdx,%rax halt

sim/y86-code/prog4.ys

# prog4: No padding irmovq $10,%rdx irmovq $3,%rax addq %rdx,%rax halt

sim/y86-code/prog5.ys

# prog5: Load/use hazard irmovq $128,%rdx irmovq $3,%rcx rmmovq %rcx, 0(%rdx) irmovq $10,%rbx mrmovq 0(%rdx), %rax # Load %rax addq %rbx,%rax # Use %rax halt

sim/y86-code/prog6.ys

# Demonstration of return # /* $begin prog6-ys */ # prog6 irmovq stack,%rsp # Initialize stack pointer call proc # Procedure call irmovq $10,%rdx # Return point halt .pos 0x20 proc: # proc: ret # Return immediately rrmovq %rdx,%rbx # Not executed .pos 0x30 stack: # stack: Stack pointer # /* $end prog6-ys */

sim/y86-code/prog7.ys

# Demonstrate branch cancellation # /* $begin prog7-ys */ # prog7 xorq %rax,%rax jne target # Not taken irmovq $1, %rax # Fall through halt target: irmovq $2, %rdx # Target irmovq $3, %rbx # Target+1 # /* $end prog7-ys */ halt

sim/y86-code/prog8.ys

# prog8: Forwarding Priority irmovq $10,%rdx irmovq $3,%rdx rrmovq %rdx,%rax halt

sim/y86-code/prog9.ys

# Exception handling # /* $begin prog9-yo */ xorq %rax,%rax jne target # Not taken irmovq $1, %rax # Fall through halt target: .byte 0xFF # Invalid instruction code # /* $end prog9-yo */

sim/y86-code/prog10.ys

# prog10 irmovq $1,%rax xorq %rsp,%rsp # Set stack pointer to 0 and CC to 100 pushq %rax # Attempt to write to 0xfffffffffffffff8 addq %rax,%rax # (Should not be executed) Would set CC to 000 irmovq $2, %rax # Not executed irmovq $3, %rax # Not executed

sim/y86-code/ret-hazard.ys

/* $begin ret-hazard-ys */ # Test instruction that modifies %esp followed by ret irmovq mem,%rbx mrmovq 0(%rbx),%rsp # Sets %rsp to point to return point ret # Returns to return point halt # rtnpt: irmovq $5,%rsi # Return point halt .pos 0x40 mem: .quad stack # Holds desired stack pointer .pos 0x50 stack: .quad rtnpt # Top of stack: Holds return point /* $end ret-hazard-ys */

sim/y86-code/README

This directory contains examples of Y86-64 assembly code programs (extension `.ys') used in Chapter 4 of CS:APP3e. Given an assembly code file "file.ys", you can assemble it with the command "make file.yo". The resulting file is in the "object code" format described in the book. You can assemble and simulate all the test programs in this directory. First, you need to make the different simulators in the pipe (psim) and seq (ssim and ssim+) directories. Then use the following commands: PIPE: make testpsim SEQ: make testssim SEQ+: make testssim+ Each of these commands will cause a number of programs to be assembled and simulated. Lots of things will scroll by, but you should see the message "ISA Check Succeeds" for each of the programs tested.

sim/y86-code/Makefile

CC=gcc CFLAGS=-Wall -O2 ISADIR = ../misc YAS=$(ISADIR)/yas YIS=$(ISADIR)/yis PIPE=../pipe/psim SEQ=../seq/ssim SEQ+ =../seq/ssim+ YOFILES = abs-asum-cmov.yo abs-asum-jmp.yo asum.yo asumr.yo asumi.yo cjr.yo j-cc.yo poptest.yo pushquestion.yo pushtest.yo prog1.yo prog2.yo prog3.yo prog4.yo prog5.yo prog6.yo prog7.yo prog8.yo prog9.yo prog10.yo ret-hazard.yo PIPEFILES = asum.pipe asumr.pipe cjr.pipe j-cc.pipe poptest.pipe pushquestion.pipe pushtest.pipe prog1.pipe prog2.pipe prog3.pipe prog4.pipe prog5.pipe prog6.pipe prog7.pipe prog8.pipe ret-hazard.pipe SEQFILES = asum.seq asumr.seq cjr.seq j-cc.seq poptest.seq pushquestion.seq pushtest.seq prog1.seq prog2.seq prog3.seq prog4.seq prog5.seq prog6.seq prog7.seq prog8.seq ret-hazard.seq SEQ+FILES = asum.seq+ asumr.seq+ cjr.seq+ j-cc.seq+ poptest.seq+ pushquestion.seq+ pushtest.seq+ prog1.seq+ prog2.seq+ prog3.seq+ prog4.seq+ prog5.seq+ prog6.seq+ prog7.seq+ prog8.seq+ ret-hazard.seq+ .SUFFIXES: .SUFFIXES: .c .s .o .ys .yo .yis .pipe .seq .seq+ all: $(YOFILES) test: testpsim testssim testssim+ testpsim: $(PIPEFILES) grep "ISA Check" *.pipe rm $(PIPEFILES) testssim: $(SEQFILES) grep "ISA Check" *.seq rm $(SEQFILES) testssim+: $(SEQ+FILES) grep "ISA Check" *.seq+ rm $(SEQ+FILES) .ys.yo: $(YAS) $*.ys .yo.yis: $(YIS) $(YIS) $*.yo > $*.yis .yo.pipe: $(PIPE) $(PIPE) -t $*.yo > $*.pipe .yo.seq: $(SEQ) $(SEQ) -t $*.yo > $*.seq .yo.seq+: $(SEQ+) $(SEQ+) -t $*.yo > $*.seq+ clean: rm -f *.o *.yis *~ *.yo *.pipe *.seq *.seq+ core

sim/ptest/README

This directory contains Perl scripts that provide comprehensive regression testing of the different Y86-64 simulators. There are four basic test types, implemented as four different scripts: optest.pl: Tests each individual instruction type jtest.pl: Tests all of the jump types under different conditions ctest.pl: Tests different pipeline control combinations htest.pl: Tests many different hazard possibilities This involves running 864+ tests, so it takes a while. Each of the tests has the following optional arguments: -s simfile Use simfile as simulator (default ../pipe/psim). -i Test the iaddq instruction You can use make to run all four test programs. Options to make include: SIM=simfile TFLAGS=<any flags you want to give to the testing scripts> For example, you could say: make SIM=../pipe/psim TFLAGS=-i to test the pipeline simulator including the iaddq instruction. (Note that this test will fail for the default implementation of pipe, since it does not implement the iaddq instruction.) When the test program detects an erroneous simulation, it leaves the .ys file in the directory (ordinarily it deletes the test code it generates). You can then run a simulator (the GUI version is especially helpful here) on one of these failing cases. Suppose the failing test is in file bad-test.ys. Then you can execute "make bad-test.yo" to create the object code, and simulate it with one of the simulators. Note that the standard test code only detects functional bugs, where the processor simulation produces different results than would be predicted by simulating at the ISA level.

sim/ptest/ctest.pl

#!/usr/bin/perl #!/usr/local/bin/perl # Test for pipeline hazard combinations use Getopt::Std; use lib "."; use tester; cmdline(); # Instruction templates $tcount = 8; @templates = ( "||jne target\n\thalt\ntarget:|", # M "|||ret", # R "||mrmovq (%rax),%rsp|ret", # G1a "|mrmovq (%rax),%rsp||ret", # G1b "mrmovq (%rax),%rsp|||ret", # G1c "||irmovq \$3,%rax|rrmovq %rax,%rdx", # G2a "|irmovq \$3,%rax||rrmovq %rax,%rdx", # G2b "irmovq \$3,%rax|||rrmovq %rax,%rdx", # G2c ); # Try combining two templates to generate test sequence sub make_test { local ($t1, $t2) = @_; $ok = 1; @test1 = split(/\|/, $t1); @test2 = split(/\|/, $t2); for ($i = 0; $i < 4; $i++) { if ($test1[$i] eq "") { if ($test2[$i] eq "") { $test[$i] = "nop"; } else { $test[$i] = $test2[$i]; } } else { if ($test2[$i] eq "") { $test[$i] = $test1[$i]; } else { if ($test1[$i] eq $test2[$i]) { # $ok = 0; $test[$i] = $test1[$i]; } else { $ok = 0; $test[$i] = "XXX"; } } } } if ($ok) { &gen_test($test[0], $test[1], $test[2], $test[3]); } } $testcnt = 0; # Generate test with 4 instructions inserted sub gen_test { local ($i1, $i2, $i3, $i4) = @_; $tname = "c-$testcnt"; $testcnt++; open(YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; print YFILE <<STUFF; irmovq Stack1,%rsp irmovq rtnpt,%rdx rmmovq %rdx,(%rsp) # Put return point on top of Stack1 irmovq Stack2,%rax rmmovq %rsp,(%rax) # Put Stack1 on top of Stack2 irmovq Stack3,%rsp # Point to Stack3 pushq %rdx rrmovq %rsp,%rbp irmovq \$3,%rdx # Initialize xorq %rbx,%rbx # Set condition codes to ZF=1,SF=0,OF=0 # Here's where the 4 instruction sequence goes $i1 $i2 $i3 $i4 # Now finish things off irmovq \$3,%rbx # Not reached when sequence ends with ret halt # rtnpt: irmovq \$5,%rsi # Return point halt .pos 0x60 Stack1: .pos 0x68 Stack2: .pos 0x70 Stack3: halt STUFF close YFILE; &run_test($tname); } $n = @templates; for ($idx1 = 0; $idx1 < $n; $idx1++) { for ($idx2 = $idx1+1; $idx2 < $n; $idx2++) { &make_test($templates[$idx1],$templates[$idx2]); } } &test_stat();

sim/ptest/htest.pl

#!/usr/bin/perl #!/usr/local/bin/perl # Test for pipeline hazards use Getopt::Std; use lib "."; use tester; cmdline(); # Destination Instructions @dest = ( # Having %rax as destination "1:rrmovq %rcx,%rax", "1:irmovq \$0x101,%rax", "1:mrmovq 0(%rbp),%rax", "1:addq %rax,%rax", "1:popq %rax", "1:cmovne %rcx,%rax", # Not taken "1:cmove %rcx,%rax", # Taken # Instructions having %rbp as destination "2:rrmovq %rax,%rbp", "2:irmovq \$0x100,%rbp", "2:mrmovq 4(%rbp),%rbp", "2:addq %rax,%rbp", "2:popq %rbp", "2:cmovne %rax,%rbp", # Not taken "2:cmove %rax,%rbp", # Taken # Instructions having %rsp as destination "3:rrmovq %rbp,%rsp", "3:irmovq \$0x104,%rsp", "3:mrmovq 4(%rbp),%rsp", "3:addq %rax,%rsp", "3:popq %rbp", "3:pushq %rax", "3:pushq %rsp", "3:popq %rsp", "1:cmovne %rbp,%rsp", # Not taken "1:cmove %rbp,%rsp" # Taken ); if ($testiaddq) { @dest = (@dest, "1:iaddq \$0x201,%rax", "2:iaddq \$0x4,%rbp", "3:iaddq \$0x4,%rsp",); } if ($testleave) { @dest = (@dest, "2:leave", "3:leave"); } @src = ( # Instructions having %rax as source "1:rrmovq %rax,%rbp", "1:rmmovq %rax,0(%rbp)", "1:rmmovq %rbp,0(%rax)", "1:mrmovq 4(%rax),%rbp", "1:addq %rax,%rbp", "1:addq %rbp,%rax", "1:addq %rax,%rax", "1:pushq %rax", # Instructions having %rbp as source "2:rrmovq %rbp,%rbp", "2:rmmovq %rbp,4(%rbp)", "2:rmmovq %rax,0(%rbp)", "2:mrmovq 8(%rbp),%rax", "2:addq %rbp,%rax", "2:addq %rax,%rbp", "2:addq %rbp,%rbp", "2:pushq %rbp", # Instructions having %rsp as source "3:rrmovq %rsp,%rbp", "3:rmmovq %rsp,4(%rbp)", "3:rmmovq %rax,-4(%rsp)", "3:mrmovq 4(%rsp),%rax", "3:addq %rsp,%rax", "3:addq %rax,%rsp", "3:addq %rsp,%rsp", "3:pushq %rsp", "3:ret" ); if ($testiaddq) { @src = (@src, "1:iaddq \$0x301,%rax", "2:iaddq \$0x8,%rbp", "3:iaddq \$0x8,%rsp"); } # Generate test with 4 instructions inserted sub gen_test { local ($i1, $i2, $i3, $i4) = @_; print YFILE <<STUFF; # Preamble. Initialize memory and registers irmovq \$0xf5,%rax irmovq \$0,%rbp rmmovq %rax,0xe0(%rbp) irmovq \$0xf7,%rax rmmovq %rax,0xe8(%rbp) irmovq \$0xfb,%rax rmmovq %rax,0xf0(%rbp) irmovq \$0xff,%rax rmmovq %rax,0xf8(%rbp) irmovq \$0x100,%rbp irmovq \$0x10c,%rsp xorq %rax,%rax # Set Z condition code irmovq \$0x80,%rax # Test 4 instruction sequence $i1 $i2 $i3 $i4 # Put in another instruction rrmovq %rsp,%rbp # Complete halt .pos 0x08 .quad pos01 .quad pos02 .quad pos03 .quad pos04 .quad pos05 .quad pos06 pos01: halt pos02: halt pos03: halt pos04: halt pos05: halt pos06: halt halt halt halt halt halt halt halt halt halt halt halt halt halt halt .pos 0x100 .quad pos11 .quad pos12 .quad pos13 .quad pos14 .quad pos15 .quad pos16 pos11: halt pos12: halt pos13: halt pos14: halt pos15: halt pos16: halt halt halt halt halt halt halt halt halt .pos 0x180 .quad pos21 .quad pos22 .quad pos23 .quad pos24 .quad pos25 .quad pos26 pos21: halt pos22: halt pos23: halt pos24: halt pos25: halt pos26: halt halt halt halt halt halt halt halt halt STUFF } # Generate pairwise tests $di = 0; $si = 0; foreach $dline (@dest) { foreach $sline (@src) { ($dtype, $d) = split /:/, $dline; ($stype, $s) = split /:/, $sline; if ($dtype == $stype) { # Two instructions with 2 nops between them $tname = "hnn-$di-$si"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; &gen_test($d, "nop", "nop", $s); close YFILE; &run_test($tname); # Two instructions with nop between them $tname = "hn-$di-$si"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; &gen_test($d, "nop", "", $s); close YFILE; &run_test($tname); # Two instructions in succession $tname = "h-$di-$si"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; &gen_test($d, "", "", $s); close YFILE; &run_test($tname); } $si++; } $si = 0; $di++; } &test_stat();

sim/ptest/jtest.pl

#!/usr/bin/perl #!/usr/local/bin/perl # Test jump instructions use Getopt::Std; use lib "."; use tester; cmdline(); @vals = (32, 64); @instr = ("jmp", "jle", "jl", "je", "jne", "jge", "jg", "call"); # Create set of forward tests foreach $t (@instr) { foreach $va (@vals) { foreach $vb (@vals) { $tname = "jf-$t-$va-$vb"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; print YFILE <<STUFF; irmovq stack, %rsp irmovq \$1, %rsi irmovq \$2, %rdi irmovq \$4, %rbp irmovq \$$va, %rax irmovq \$$vb, %rdx subq %rdx,%rax $t target addq %rsi,%rax addq %rdi,%rax addq %rbp,%rax halt target: addq %rsi,%rdx addq %rdi,%rdx addq %rbp,%rdx nop nop halt .pos 0x100 stack: STUFF close YFILE; &run_test($tname); } } } # Create set of backward tests foreach $t (@instr) { foreach $va (@vals) { foreach $vb (@vals) { $tname = "jb-$t-$va-$vb"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; print YFILE <<STUFF; irmovq stack, %rsp irmovq \$1, %rsi irmovq \$2, %rdi irmovq \$4, %rbp irmovq \$$va, %rax irmovq \$$vb, %rdx jmp skip halt target: addq %rsi,%rdx addq %rdi,%rdx addq %rbp,%rdx nop nop halt skip: subq %rdx,%rax $t target addq %rsi,%rax addq %rdi,%rax addq %rbp,%rax halt .pos 0x100 stack: STUFF close YFILE; &run_test($tname); } } } if ($testiaddq) { # Create set of forward tests using iaddq foreach $t (@instr) { foreach $va (@vals) { foreach $vb (@vals) { $tname = "ji-$t-$va-$vb"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; print YFILE <<STUFF; irmovq stack, %rsp irmovq \$1, %rsi irmovq \$2, %rdi irmovq \$4, %rbp irmovq \$$va, %rax iaddq \$-$vb,%rax $t target addq %rsi,%rax addq %rdi,%rax addq %rbp,%rax halt target: addq %rsi,%rdx addq %rdi,%rdx addq %rbp,%rdx nop nop halt .pos 0x100 stack: STUFF close YFILE; &run_test($tname); } } } } &test_stat();

sim/ptest/optest.pl

#!/usr/bin/perl #!/usr/local/bin/perl # Test single instructions in pipeline use Getopt::Std; use lib "."; require tester; cmdline(); @vals = (0x100, 0x020, 0x004); @instr = ("rrmovq", "addq", "subq", "andq", "xorq"); @regs = ("rdx", "rbx", "rsp"); foreach $t (@instr) { foreach $ra (@regs) { foreach $rb (@regs) { $tname = "op-$t-$ra-$rb"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; print YFILE <<STUFF; irmovq \$$vals[0], %$ra irmovq \$$vals[1], %$rb nop nop nop $t %$ra,%$rb nop nop halt STUFF close YFILE; run_test($tname); } } } if ($testiaddq) { foreach $ra (@regs) { foreach $val (@vals) { $tname = "op-iaddq-$val-$ra"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; print YFILE <<STUFF; irmovq \$$val, %$ra nop nop nop iaddq \$-32, %$ra nop nop halt STUFF close YFILE; run_test($tname); } } } @instr = ("pushq", "popq"); @regs = ("rdx", "rsp"); foreach $t (@instr) { foreach $ra (@regs) { $tname = "op-$t-$ra"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; print YFILE <<STUFF; irmovq \$0x200,%rsp irmovq \$$vals[1], %rax nop nop nop rmmovq %rax, 0(%rsp) irmovq \$$vals[2], %rax nop nop nop rmmovq %rax, -4(%rsp) irmovq \$$vals[0], %rdx nop nop nop $t %$ra nop nop halt STUFF close YFILE; &run_test($tname); } } &test_stat();

sim/ptest/etest.pl

#!/usr/bin/perl #!/usr/local/bin/perl # Test for exception followed by state-setting instruction use Getopt::Std; use lib "."; use tester; cmdline(); # State setting instructions @stateset = ( # Set condition codes "andq %rcx,%rcx", # Write to memory "rmmovq %rcx,(%rax)" ); # Exception causing instructions @exceptset = ( # halt "halt", # Invalid instruction ".byte 0xFF", # Invalid write address "rmmovq %rax,0xF0000000(%rax)" ); # Generate test with 3 instructions inserted sub gen_test { local ($i1, $i2, $i3) = @_; print YFILE <<STUFF; # Preamble. Initialize memory and registers irmovq \$-1,%rcx # Create nonzero value irmovq \$0x100,%rax xorq %rdx,%rdx # Set Z condition code # Test 3 instruction sequence $i1 $i2 $i3 # Complete nop nop halt STUFF } # Generate pairwise tests $ei = 0; $si = 0; foreach $e (@exceptset) { foreach $s (@stateset) { # Two instructions with 1 nop between them $tname = "en-$ei-$si"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; &gen_test($e, "nop", $s); close YFILE; &run_test($tname); # Two instructions in succession $tname = "e-$ei-$si"; open (YFILE, ">$tname.ys") || die "Can't write to $tname.ys\n"; &gen_test($e, "", $s); close YFILE; &run_test($tname); $si++; } $si = 0; $ei++; } &test_stat();

sim/ptest/tester.pm

# Configuration information for processor tests. # Common declarations for testing code # Where's the assembler? $yas = "../misc/yas"; # Which simulator is being tested? $sim = "../pipe/psim"; # By default, don't test iaddq instruction. $testiaddq = 0; # Where should result files be placed? $outputdir = "."; # Generate performance targets? $gen_perf = 0; # Check performance targets? $check_perf = 0; # File with performance targets $perf_file = ""; # Should this be a test of a Verilog implementation? $test_vlog = 0; # What model should be used for Verilog? $vmodel = "pipe-std"; # What program does the Verilog testing $vtest = "../verilog/test-sim.pl"; $tcount = 0; $ecount = 0; $pecount = 0; sub run_test { local ($tname) = @_; ## print("Running test $tname\n"); if ($test_vlog) { &run_vlog_test($tname); } else { &run_sim_test($tname); } } sub run_sim_test { local ($tname) = @_; system "$yas $tname.ys" || die "Can't open file $tname.ys\n"; local $result = `$sim -v 0 -t $tname.yo`; if (!($result =~ "Succeed")) { print "Test $tname failed\n"; $ecount++; if (!($outputdir eq ".")) { system "mv $tname.ys $outputdir"; } } else { system "rm $tname.ys"; } if ($gen_perf) { $_ = $result; m#CPI:[^0-9]*([0-9]+)[^0-9]*([0-9]+)#; $cycles = $1; $instructions = $2; print "$tname:$cycles:$instructions\n"; } if ($check_perf) { $_ = $result; m#CPI:[^0-9]*([0-9]+)[^0-9]*([0-9]+)#; $tcycles = $1; $tinstructions = $2; $p = `grep $tname $perf_file` || die "Couldn't open file $perf_file\n"; chomp $p; ($pname, $pcycles, $pinstructions) = split /:/, $p; if ($tcycles != $pcycles) { $pecount++; print "Test $tname.\tMeasured cycles=$tcycles != Target cycles=$pcycles\n"; } } $tcount++; system "rm $tname.yo"; } sub run_vlog_test { local ($tname) = @_; local $proc; local $version; local $dir; local $flags = ""; if ($vmodel =~ /(pipe|seq|seq\+)-(.*)/) { $proc = $1; $version = $2; if ($proc =~ "seq") { $dir = "seq"; } else { $dir = "pipe"; } $flags = "-p ../verilog/components/$proc-proc.v -H ../$dir/$proc-$version.hcl"; } print "Running '$vtest -a $tname $flags'\n"; local $result = `$vtest -a $tname $flags`; if (!($result =~ "Results match")) { print "Test $tname failed\n"; $ecount++; if (!($outputdir eq ".")) { system "mv $tname.ys $outputdir"; } } else { system "rm $tname.ys"; } $tcount++; } sub test_stat { if ($ecount == 0) { print " All $tcount ISA Checks Succeed\n"; } else { print " $ecount/$tcount ISA Checks Failed\n"; } if ($check_perf) { if ($pecount == 0) { print " All $tcount Performance Checks Succeed\n"; } else { print " $pecount/$tcount Performance Checks Failed\n"; } } } sub cmdline { # parse command line arguments getopts('his:Pp:d:Vm:'); if ($opt_h) { print STDERR "Usage $argv[0] [-h] [-i] [-s <sim>] [-P] [-p <pfile>]\n"; print STDERR " -h print Help message\n"; print STDERR " -i test iaddq instruction\n"; print STDERR " -s <sim> Specify simulator\n"; print STDERR " -d <dir> Specify directory for counterexamples\n"; print STDERR " -P Generate performance data\n"; print STDERR " -p <version> Check using performance file <pfile>\n"; print STDERR " -V test Verilog implementation\n"; print STDERR " -m <model> Model for Verilog\n"; die "\n"; } if ($opt_i) { $testiaddq = 1; } if ($opt_d) { $outputdir = $opt_d; } if ($opt_P) { $gen_perf = 1; } if ($opt_p) { $check_perf = 1; $perf_file = $opt_p; } if ($opt_s) { $sim = $opt_s; } if ($opt_V) { $test_vlog = 1; if ($opt_m) { $vmodel = $opt_m; } } else { print "Simulating with $sim\n"; } } # Perl gives error messages without the following line !?! $junk = 1;

sim/ptest/Makefile

SIM=../pipe/psim TFLAGS= ISADIR = ../misc YAS=$(ISADIR)/yas .SUFFIXES: .ys .yo .ys.yo: $(YAS) $*.ys test: ./optest.pl -s $(SIM) $(TFLAGS) ./jtest.pl -s $(SIM) $(TFLAGS) ./ctest.pl -s $(SIM) $(TFLAGS) ./htest.pl -s $(SIM) $(TFLAGS) clean: rm -f *.o *~ *.yo *.ys

sim/Makefile

# Comment this out if you don't have Tcl/Tk on your system #GUIMODE=-DHAS_GUI # Modify the following line so that gcc can find the libtcl.so and # libtk.so libraries on your system. You may need to use the -L option # to tell gcc which directory to look in. Comment this out if you # don't have Tcl/Tk. #TKLIBS=-L/usr/lib -ltk -ltcl # Modify the following line so that gcc can find the tcl.h and tk.h # header files on your system. Comment this out if you don't have # Tcl/Tk. i#TKINC=-isystem /usr/include/tcl8.5 ################################################## # You shouldn't need to modify anything below here ################################################## # Use this rule (make all) to build the Y86-64 tools. The variables you've # assigned to GUIMODE, TKLIBS, and TKINC will override the values that # are currently assigned in seq/Makefile and pipe/Makefile. all: (cd misc; make all) (cd pipe; make all GUIMODE=$(GUIMODE) TKLIBS="$(TKLIBS)" TKINC="$(TKINC)") (cd seq; make all GUIMODE=$(GUIMODE) TKLIBS="$(TKLIBS)" TKINC="$(TKINC)") (cd y86-code; make all) clean: rm -f *~ core (cd misc; make clean) (cd pipe; make clean) (cd seq; make clean) (cd y86-code; make clean) (cd ptest; make clean)

sim/README

/*********************************************************************** * Y86-64 Tools (Student Distribution) * * Copyright (c) 2002, 2010, 2015, R. Bryant and D. O'Hallaron, * All rights reserved. May not be used, modified, or copied * without permission. ***********************************************************************/ This directory contains the student distribution of the Y86-64 tools. It is a proper subset of the master distribution, minus the solution files found in the master distribution. yas Y86-64 assembler yis Y86-64 instruction (ISA) simulator hcl2c HCL to C translator hcl2v HCL to Verilog translator ssim SEQ simulator ssim+ SEQ+ simulator psim PIPE simulator ************************* 1. Building the Y86-64 tools ************************* The Y86-64 simulators can be configured to support TTY and GUI interfaces. A simulator running in TTY mode prints all information about its run-time behavior on the terminal. It's harder to understand what's going on, but useful for automated testing, and doesn't require any special installation features. A simulator running in GUI mode uses a fancy graphical user interface. Nice for visualizing and debugging, but requires installation of Tcl/Tk on your system. To build the Y86-64 tools, perform the following steps: NOTE: If your instructor prepared this distribution for you, then you can skip Step 1 and proceed directly to Step 2. The Makefile will already have the proper values for GUIMODE, TKLIBS, and TKINC for your system. Step 1. Decide whether you want the TTY or GUI form of the simulators, and then modify ./Makefile in this directory accordingly. (The changes you make to the variables in this Makefile will override the values already assigned in the Makefiles in the seq and pipe directories.) Building the GUI simulators: If you have Tcl/Tk installed on your system, then you can build the GUI form by initializing the GUIMODE, TKLIBS, and TKINC variables, as appropriate for your system. (The default values work for Linux systems.) Assigning GUIMODE=-DHAS_GUI causes the necessary GUI support code in the simulator sources to be included. The TKLIBS variable tells gcc where to look for the libtcl.so and libtk.so libraries. And the TKINC variable tells gcc where to find the tcl.h and tk.h header files. Building the TTY simulators: If you don't have Tcl/Tk installed on your system, then build the TTY form by commenting out all three of these variables (GUIMODE, TKLIBS, and TKINC) in the Makefile. Step 2: Once you've modified the Makefile to build either the GUI or TTY form, then you can construct the entire set of Y86-64 tools by typing unix> make clean; make ******** 2. Files ******** Makefile Builds the Y86-64 tools README This file misc/ Source files for the Y86-64 assembler yas, the Y86-64 instruction simulator yis, and the isa.c file that is used by the -t option of the processor simulators to check the results against the ISA simulation. Also contains files for the programs hcl2c and hcl2v seq/ Code for the SEQ and SEQ+ simulators. Contains HCL files for labs and homework problems that involve modifying SEQ. pipe/ Code for the PIPE simulator. Contains HCL files for labs and homework problems that involve modifying PIPE. y86-code/ Example .ys files from CS:APP and scripts for conducting automated benchmark teseting of the new processor designs. ptest/ Automated regression testing scripts for testing processor designs. verilog/ System for producing Verilog designs from HCL code