This commit is contained in:
Michael Zhang 2018-01-29 17:45:27 -06:00
commit 1fa36db752
No known key found for this signature in database
GPG key ID: A1B65B603268116B
238 changed files with 1790530 additions and 0 deletions

BIN
ArchLab/._archlab-handout Executable file

Binary file not shown.

Binary file not shown.

BIN
ArchLab/archlab-handout/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,36 @@
####################################################
# Students' Makefile for the CS:APP Architecture Lab
####################################################
X500 = replace_this_with_your_x500_id
VERSION = 1
# Where are the different parts of the lab should be copied to when they
# are handed in.
HANDINDIR-PARTA = ../archlab-handout
HANDINDIR-PARTB = ../archlab-handout
HANDINDIR-PARTC = ../archlab-handout
sim:
(cd sim; make)
# Use this rule to hand in Part A ("make handin-parta")
handin-parta:
cp sim/misc/sum.ys $(HANDINDIR-PARTA)/$(X500)-sum.ys
cp sim/misc/rsum.ys $(HANDINDIR-PARTA)/$(X500)-rsum.ys
cp sim/misc/copy.ys $(HANDINDIR-PARTA)/$(X500)-copy.ys
# Use this rule to handin Part B ("make handin-partb")
handin-partb:
cp sim/seq/seq-full.hcl $(HANDINDIR-PARTB)/$(X500)-seq-full.hcl
# Use this rule to handin Part C ("make handin-partc")
handin-partc:
cp sim/pipe/ncopy.ys $(HANDINDIR-PARTC)/$(X500)-ncopy.ys
cp sim/pipe/pipe-full.hcl $(HANDINDIR-PARTC)/$(X500)-pipe-full.hcl
clean:
rm -f *~ *.o

View file

@ -0,0 +1,22 @@
#####################################################################
# CS:APP Architecture Lab
# Handout files for students
#
# 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 files that you need for the CS:APP
architecture lab.
******
Files:
******
Makefile Use this to handin your solutions
README This file
archlab.{ps,pdf} Lab writeup
sim.tar Archive of the Y86-64 tools in tar format
simguide.{ps,pdf} CS:APP Guide to Simulators document

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,38 @@
# 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/tk
##################################################
# 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)

View file

@ -0,0 +1,97 @@
/***********************************************************************
* 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

View file

@ -0,0 +1,59 @@
CC=/usr/bin/gcc
CFLAGS=-Wall -O1 -g -DUSE_INTERP_RESULT
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

View file

@ -0,0 +1,71 @@
/***********************************************************************
* 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}

View file

@ -0,0 +1,45 @@
# by Michael Zhang <zhan4854@umn.edu>
# Execution begins at address 0
.pos 0
irmovq stack, %rsp
call main
halt
.align 8
# Source block
src:
.quad 0x001
.quad 0x002
.quad 0x004
# Destination block
dest:
.quad 0x111
.quad 0x222
.quad 0x333
main:
irmovq src, %rdi
irmovq dest, %rsi
irmovq $3, %rdx
call copy
ret
copy:
irmovq $1, %r8 # decrement len
irmovq $8, %rcx # increment address
xorq %rax, %rax
andq %rdx, %rdx
jne test
loop:
mrmovq (%rdi), %r9
addq %rcx, %rdi
rmmovq %r9, (%rsi)
addq %rcx, %rsi
xorq %r9, %rax
subq %r8, %rdx
test:
jne loop
ret
.pos 0x200
stack:

View file

@ -0,0 +1,50 @@
/*
* 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 */

View file

@ -0,0 +1,45 @@
%{
#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);
%%

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,86 @@
/* A Bison parser, made by GNU Bison 3.0.4. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015 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
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
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
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;
int yyparse (void);
#endif /* !YY_YY_HCL_TAB_H_INCLUDED */

View file

@ -0,0 +1,96 @@
%{
#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));}

Binary file not shown.

View file

@ -0,0 +1,943 @@
#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;
}

View file

@ -0,0 +1,210 @@
/* 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

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,57 @@
#/* $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 */

View file

@ -0,0 +1,703 @@
/* 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 */
}

View file

@ -0,0 +1,35 @@
#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

View file

@ -0,0 +1,71 @@
#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;
}

View file

@ -0,0 +1,18 @@
/* 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();

View file

@ -0,0 +1,40 @@
# by Michael Zhang <zhan4854@umn.edu>
# Execution begins at address 0
.pos 0
irmovq stack, %rsp
call main
halt
# Sample linked list
.align 8
ele1:
.quad 0xa00
.quad ele2
ele2:
.quad 0x0b0
.quad ele3
ele3:
.quad 0x00c
.quad 0
main:
irmovq ele1, %rdi # copy the first element
xorq %rax, %rax # set %rax to 0
call rsum_list # call rsum_list
ret
rsum_list:
mrmovq (%rdi), %r8
mrmovq 8(%rdi), %r9
addq %r8, %rax
xorq %rdi, %rdi
addq %r9, %rdi
jne recall
ret
recall:
call rsum_list
ret
.pos 0x200
stack:

View file

@ -0,0 +1,40 @@
# by Michael Zhang <zhan4854@umn.edu>
# Based on asum.ys from the the examples
# Execution begins at address 0
.pos 0
irmovq stack, %rsp
call main
halt
# Sample linked list
.align 8
ele1:
.quad 0xa00
.quad ele2
ele2:
.quad 0x0b0
.quad ele3
ele3:
.quad 0x00c
.quad 0
main:
irmovq ele1, %rdi # copy the first element
call sum_list # call sum_list
ret
sum_list:
xorq %rax, %rax # set %rax to 0
loop:
mrmovq (%rdi), %r8 # move the number into %r8
mrmovq 8(%rdi), %r9 # move the address into %r9
addq %r8, %rax # add to %rax
xorq %rdi, %rdi # unset %rdi
addq %r9, %rdi # add the address to %rdi, which also sets ZF
test:
jne loop # jump if the address isn't 0 (more elements)
ret
.pos 0x200
stack:

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
/* 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));
}

Binary file not shown.

View file

@ -0,0 +1,625 @@
/* 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 (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);
}

View file

@ -0,0 +1,13 @@
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;

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,64 @@
/* 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;
}

Binary file not shown.

View file

@ -0,0 +1,63 @@
# Modify this line to indicate the default version to build
VERSION=full
# 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/tk
# Modify these two lines to choose your compiler and compile time
# flags.
CC=/usr/bin/gcc
CFLAGS=-Wall -O2 -DUSE_INTERP_RESULT
##################################################
# 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 *~

View file

@ -0,0 +1,150 @@
/***********************************************************************
* 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

View file

@ -0,0 +1,110 @@
#!/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 = 8.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;

View file

@ -0,0 +1,25 @@
#!/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";
}

View file

@ -0,0 +1,139 @@
#!/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;
exit(0);
}
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";

View file

@ -0,0 +1,208 @@
| #######################################################################
| # Test for copying block of size 3;
| #######################################################################
0x000: | .pos 0
0x000: 30f49803000000000000 | main: irmovq Stack, %rsp # Set up stack pointer
|
| # Set up arguments for copy function and then invoke it
0x00a: 30f20300000000000000 | irmovq $3, %rdx # src and dst have 3 elements
0x014: 30f6f802000000000000 | irmovq dest, %rsi # dst array
0x01e: 30f7c802000000000000 | irmovq src, %rdi # src array
0x028: 803b00000000000000 | call ncopy
0x031: 805c01000000000000 | call check # Call checker code
0x03a: 00 | halt # should halt with 0xaaaa in %rax
0x03b: | StartFun:
| #/* $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
0x03b: | ncopy:
|
| ##################################################################
| # You can modify this portion
| # Loop header
0x03b: 6300 | xorq %rax,%rax # count = 0;
0x03d: 6222 | andq %rdx,%rdx # len <= 0?
0x03f: 715b01000000000000 | jle Done # if so, goto Done:
0x048: c0f2fbffffffffffffff | iaddq $-5, %rdx # Check if it goes negative
0x052: 724f01000000000000 | jl Last5
|
0x05b: | MainLoop:
0x05b: 50870000000000000000 | mrmovq (%rdi), %r8
0x065: 50970800000000000000 | mrmovq 8(%rdi), %r9
0x06f: 50a71000000000000000 | mrmovq 16(%rdi), %r10
0x079: 50b71800000000000000 | mrmovq 24(%rdi), %r11
0x083: 50c72000000000000000 | mrmovq 32(%rdi), %r12
|
0x08d: 40860000000000000000 | rmmovq %r8, (%rsi)
0x097: 40960800000000000000 | rmmovq %r9, 8(%rsi)
0x0a1: 40a61000000000000000 | rmmovq %r10, 16(%rsi)
0x0ab: 40b61800000000000000 | rmmovq %r11, 24(%rsi)
0x0b5: 40c62000000000000000 | rmmovq %r12, 32(%rsi)
|
0x0bf: 6288 | andq %r8, %r8
0x0c1: 71d400000000000000 | jle N2
0x0ca: c0f00100000000000000 | iaddq $1, %rax
0x0d4: | N2:
0x0d4: 6299 | andq %r9, %r9
0x0d6: 71e900000000000000 | jle N3
0x0df: c0f00100000000000000 | iaddq $1, %rax
0x0e9: | N3:
0x0e9: 62aa | andq %r10, %r10
0x0eb: 71fe00000000000000 | jle N4
0x0f4: c0f00100000000000000 | iaddq $1, %rax
0x0fe: | N4:
0x0fe: 62bb | andq %r11, %r11
0x100: 711301000000000000 | jle N5
0x109: c0f00100000000000000 | iaddq $1, %rax
0x113: | N5:
0x113: 62cc | andq %r12, %r12
0x115: 712801000000000000 | jle Final
0x11e: c0f00100000000000000 | iaddq $1, %rax
|
0x128: | Final:
0x128: c0f72800000000000000 | iaddq $40, %rdi
0x132: c0f62800000000000000 | iaddq $40, %rsi
0x13c: c0f2fbffffffffffffff | iaddq $-5, %rdx
0x146: 755b00000000000000 | jge MainLoop
|
0x14f: | Last5:
0x14f: c0f20500000000000000 | iaddq $5, %rdx # Restore from negative
0x159: 6311 | xorq %rcx, %rcx
|
|
| ##################################################################
| # Do not modify the following section of code
| # Function epilogue.
0x15b: | Done:
0x15b: 90 | ret
| ##################################################################
| # Keep the following label at the end of your function
0x15c: | End:
| #/* $end ncopy-ys */
|
0x15c: | EndFun:
| ####################################################################
| # Epilogue code for the correctness testing driver
| ####################################################################
|
| # This is the correctness checking code.
| # It checks:
| # 1. %rax has 3. Set %rax to 0xbbbb if not.
| # 2. The total length of the code is less than or equal to 1000.
| # 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
0x15c: | check:
| # Return value test
0x15c: 30fa0300000000000000 | irmovq $3,%r10
0x166: 61a0 | subq %r10,%rax
0x168: 738401000000000000 | je checkb
0x171: 30f0bbbb000000000000 | irmovq $0xbbbb,%rax # Failed test #1
0x17b: 70c202000000000000 | jmp cdone
0x184: | checkb:
| # Code length check
0x184: 30f05c01000000000000 | irmovq EndFun,%rax
0x18e: 30f23b00000000000000 | irmovq StartFun,%rdx
0x198: 6120 | subq %rdx,%rax
0x19a: 30f2e803000000000000 | irmovq $1000,%rdx
0x1a4: 6102 | subq %rax,%rdx
0x1a6: 75c201000000000000 | jge checkm
0x1af: 30f0cccc000000000000 | irmovq $0xcccc,%rax # Failed test #2
0x1b9: 70c202000000000000 | jmp cdone
0x1c2: | checkm:
0x1c2: 30f2f802000000000000 | irmovq dest, %rdx # Pointer to next destination location
0x1cc: 30f3c802000000000000 | irmovq src,%rbx # Pointer to next source location
0x1d6: 30f70300000000000000 | irmovq $3,%rdi # Count
0x1e0: 6277 | andq %rdi,%rdi
0x1e2: 734002000000000000 | je checkpre # Skip check if count = 0
0x1eb: | mcloop:
0x1eb: 50020000000000000000 | mrmovq (%rdx),%rax
0x1f5: 50630000000000000000 | mrmovq (%rbx),%rsi
0x1ff: 6160 | subq %rsi,%rax
0x201: 731d02000000000000 | je mok
0x20a: 30f0dddd000000000000 | irmovq $0xdddd,%rax # Failed test #3
0x214: 70c202000000000000 | jmp cdone
0x21d: | mok:
0x21d: 30f00800000000000000 | irmovq $8,%rax
0x227: 6002 | addq %rax,%rdx # dest ++
0x229: 6003 | addq %rax,%rbx # src++
0x22b: 30f00100000000000000 | irmovq $1,%rax
0x235: 6107 | subq %rax,%rdi # cnt--
0x237: 76eb01000000000000 | jg mcloop
0x240: | checkpre:
| # Check for corruption
0x240: 30f2f002000000000000 | irmovq Predest,%rdx
0x24a: 50020000000000000000 | mrmovq (%rdx), %rax # Get word before destination
0x254: 30f2fadebc0000000000 | irmovq $0xbcdefa, %rdx
0x25e: 6120 | subq %rdx,%rax
0x260: 737c02000000000000 | je checkpost
0x269: 30f0eeee000000000000 | irmovq $0xeeee,%rax # Failed test #4
0x273: 70c202000000000000 | jmp cdone
0x27c: | checkpost:
| # Check for corruption
0x27c: 30f21003000000000000 | irmovq Postdest,%rdx
0x286: 50020000000000000000 | mrmovq (%rdx), %rax # Get word after destination
0x290: 30f2bcfade0000000000 | irmovq $0xdefabc, %rdx
0x29a: 6120 | subq %rdx,%rax
0x29c: 73b802000000000000 | je checkok
0x2a5: 30f0eeee000000000000 | irmovq $0xeeee,%rax # Failed test #4
0x2af: 70c202000000000000 | jmp cdone
0x2b8: | checkok:
| # Successful checks
0x2b8: 30f0aaaa000000000000 | irmovq $0xaaaa,%rax
0x2c2: | cdone:
0x2c2: 90 | ret
|
| ###############################
| # Source and destination blocks
| ###############################
0x2c8: | .align 8
0x2c8: | src:
0x2c8: 0100000000000000 | .quad 1
0x2d0: 0200000000000000 | .quad 2
0x2d8: 0300000000000000 | .quad 3
0x2e0: fadebc0000000000 | .quad 0xbcdefa # This shouldn't get moved
|
0x2f0: | .align 16
0x2f0: | Predest:
0x2f0: fadebc0000000000 | .quad 0xbcdefa
0x2f8: | dest:
0x2f8: abefcd0000000000 | .quad 0xcdefab
0x300: abefcd0000000000 | .quad 0xcdefab
0x308: abefcd0000000000 | .quad 0xcdefab
0x310: | Postdest:
0x310: bcfade0000000000 | .quad 0xdefabc
|
0x318: | .align 8
| # Run time stack
0x318: 0000000000000000 | .quad 0
0x320: 0000000000000000 | .quad 0
0x328: 0000000000000000 | .quad 0
0x330: 0000000000000000 | .quad 0
0x338: 0000000000000000 | .quad 0
0x340: 0000000000000000 | .quad 0
0x348: 0000000000000000 | .quad 0
0x350: 0000000000000000 | .quad 0
0x358: 0000000000000000 | .quad 0
0x360: 0000000000000000 | .quad 0
0x368: 0000000000000000 | .quad 0
0x370: 0000000000000000 | .quad 0
0x378: 0000000000000000 | .quad 0
0x380: 0000000000000000 | .quad 0
0x388: 0000000000000000 | .quad 0
0x390: 0000000000000000 | .quad 0
|
0x398: | Stack:

View file

@ -0,0 +1,208 @@
#######################################################################
# Test for copying block of size 3;
#######################################################################
.pos 0
main: irmovq Stack, %rsp # Set up stack pointer
# Set up arguments for copy function and then invoke it
irmovq $3, %rdx # src and dst have 3 elements
irmovq dest, %rsi # dst array
irmovq src, %rdi # src array
call ncopy
call check # Call checker code
halt # should halt with 0xaaaa in %rax
StartFun:
#/* $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:
iaddq $-5, %rdx # Check if it goes negative
jl Last5
MainLoop:
mrmovq (%rdi), %r8
mrmovq 8(%rdi), %r9
mrmovq 16(%rdi), %r10
mrmovq 24(%rdi), %r11
mrmovq 32(%rdi), %r12
rmmovq %r8, (%rsi)
rmmovq %r9, 8(%rsi)
rmmovq %r10, 16(%rsi)
rmmovq %r11, 24(%rsi)
rmmovq %r12, 32(%rsi)
andq %r8, %r8
jle N2
iaddq $1, %rax
N2:
andq %r9, %r9
jle N3
iaddq $1, %rax
N3:
andq %r10, %r10
jle N4
iaddq $1, %rax
N4:
andq %r11, %r11
jle N5
iaddq $1, %rax
N5:
andq %r12, %r12
jle Final
iaddq $1, %rax
Final:
iaddq $40, %rdi
iaddq $40, %rsi
iaddq $-5, %rdx
jge MainLoop
Last5:
iaddq $5, %rdx # Restore from negative
xorq %rcx, %rcx
##################################################################
# 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 */
EndFun:
####################################################################
# Epilogue code for the correctness testing driver
####################################################################
# This is the correctness checking code.
# It checks:
# 1. %rax has 3. Set %rax to 0xbbbb if not.
# 2. The total length of the code is less than or equal to 1000.
# 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 $3,%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 $1000,%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 $3,%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 $0xbcdefa, %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 $0xdefabc, %rdx
subq %rdx,%rax
je checkok
irmovq $0xeeee,%rax # Failed test #4
jmp cdone
checkok:
# Successful checks
irmovq $0xaaaa,%rax
cdone:
ret
###############################
# Source and destination blocks
###############################
.align 8
src:
.quad 1
.quad 2
.quad 3
.quad 0xbcdefa # This shouldn't get moved
.align 16
Predest:
.quad 0xbcdefa
dest:
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
Postdest:
.quad 0xdefabc
.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:

View file

@ -0,0 +1,252 @@
#!/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;
$poscount = 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++;
$poscount++;
}
} else {
if ($rval < $tval && int(rand(2)) % 2 == 1 ||
$tval - $rval >= $n - $i) {
$data[$i] = -$data[$i];
$rval++;
$poscount++;
}
}
}
$rval = $poscount;
# 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

View file

@ -0,0 +1,292 @@
| #######################################################################
| # Test for copying block of size 63;
| #######################################################################
0x000: | .pos 0
0x000: 30f4c806000000000000 | main: irmovq Stack, %rsp # Set up stack pointer
|
| # Set up arguments for copy function and then invoke it
0x00a: 30f23f00000000000000 | irmovq $63, %rdx # src and dst have 63 elements
0x014: 30f64804000000000000 | irmovq dest, %rsi # dst array
0x01e: 30f73802000000000000 | irmovq src, %rdi # src array
0x028: 803200000000000000 | call ncopy
0x031: 00 | halt # should halt with num nonzeros in %rax
0x032: | StartFun:
| #/* $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.
| # Michael Zhang <zhan4854@umn.edu>
| #
| # Firstly, I made use of iaddq, in order to prevent having to store
| # constants into memory in order to add them. This reduces the number
| # of instructions required for incrementing counters. This got my
| # CPE down to about 12.7.
| #
| # I also used the loop unrolling technique to unroll the loop 5
| # times. Because it was easy to use jle to compare to 0, I kept
| # processing 5 elements at a time until I got to the last 4, at
| # which point the counter would go negative. Then I would manually
| # add back and execute the instructions 1-by-1 (since there are
| # only at most 4 left).
| #
| ##################################################################
| # Do not modify this portion
| # Function prologue.
| # %rdi = src, %rsi = dst, %rdx = len
0x032: | ncopy:
|
| ##################################################################
| # You can modify this portion
| # Loop header
0x032: 6300 | xorq %rax,%rax # count = 0;
0x034: 6222 | andq %rdx,%rdx # len <= 0?
0x036: 713602000000000000 | jle Done # if so, goto Done:
0x03f: c0f2fbffffffffffffff | iaddq $-5, %rdx # Check if it goes negative
0x049: 724601000000000000 | jl Last4
|
0x052: | MainLoop:
0x052: 50870000000000000000 | mrmovq (%rdi), %r8
0x05c: 50970800000000000000 | mrmovq 8(%rdi), %r9
0x066: 50a71000000000000000 | mrmovq 16(%rdi), %r10
0x070: 50b71800000000000000 | mrmovq 24(%rdi), %r11
0x07a: 50c72000000000000000 | mrmovq 32(%rdi), %r12
|
0x084: 40860000000000000000 | rmmovq %r8, (%rsi)
0x08e: 40960800000000000000 | rmmovq %r9, 8(%rsi)
0x098: 40a61000000000000000 | rmmovq %r10, 16(%rsi)
0x0a2: 40b61800000000000000 | rmmovq %r11, 24(%rsi)
0x0ac: 40c62000000000000000 | rmmovq %r12, 32(%rsi)
|
0x0b6: 6288 | andq %r8, %r8
0x0b8: 71cb00000000000000 | jle N2
0x0c1: c0f00100000000000000 | iaddq $1, %rax
0x0cb: | N2:
0x0cb: 6299 | andq %r9, %r9
0x0cd: 71e000000000000000 | jle N3
0x0d6: c0f00100000000000000 | iaddq $1, %rax
0x0e0: | N3:
0x0e0: 62aa | andq %r10, %r10
0x0e2: 71f500000000000000 | jle N4
0x0eb: c0f00100000000000000 | iaddq $1, %rax
0x0f5: | N4:
0x0f5: 62bb | andq %r11, %r11
0x0f7: 710a01000000000000 | jle N5
0x100: c0f00100000000000000 | iaddq $1, %rax
0x10a: | N5:
0x10a: 62cc | andq %r12, %r12
0x10c: 711f01000000000000 | jle Final
0x115: c0f00100000000000000 | iaddq $1, %rax
|
0x11f: | Final:
0x11f: c0f72800000000000000 | iaddq $40, %rdi
0x129: c0f62800000000000000 | iaddq $40, %rsi
0x133: c0f2fbffffffffffffff | iaddq $-5, %rdx
0x13d: 755200000000000000 | jge MainLoop
|
0x146: | Last4:
0x146: c0f20400000000000000 | iaddq $4, %rdx # Restore from negative
0x150: 723602000000000000 | jl Done
0x159: 50870000000000000000 | mrmovq (%rdi), %r8
0x163: 40860000000000000000 | rmmovq %r8, (%rsi)
0x16d: 6288 | andq %r8, %r8
0x16f: 718201000000000000 | jle Last3
0x178: c0f00100000000000000 | iaddq $1, %rax
0x182: | Last3:
0x182: c0f2ffffffffffffffff | iaddq $-1, %rdx
0x18c: 723602000000000000 | jl Done
0x195: 50870800000000000000 | mrmovq 8(%rdi), %r8
0x19f: 40860800000000000000 | rmmovq %r8, 8(%rsi)
0x1a9: 6288 | andq %r8, %r8
0x1ab: 71be01000000000000 | jle Last2
0x1b4: c0f00100000000000000 | iaddq $1, %rax
0x1be: | Last2:
0x1be: c0f2ffffffffffffffff | iaddq $-1, %rdx
0x1c8: 723602000000000000 | jl Done
0x1d1: 50871000000000000000 | mrmovq 16(%rdi), %r8
0x1db: 40861000000000000000 | rmmovq %r8, 16(%rsi)
0x1e5: 6288 | andq %r8, %r8
0x1e7: 71fa01000000000000 | jle Last1
0x1f0: c0f00100000000000000 | iaddq $1, %rax
0x1fa: | Last1:
0x1fa: c0f2ffffffffffffffff | iaddq $-1, %rdx
0x204: 723602000000000000 | jl Done
0x20d: 50871800000000000000 | mrmovq 24(%rdi), %r8
0x217: 40861800000000000000 | rmmovq %r8, 24(%rsi)
0x221: 6288 | andq %r8, %r8
0x223: 713602000000000000 | jle Done
0x22c: c0f00100000000000000 | iaddq $1, %rax
|
| ##################################################################
| # Do not modify the following section of code
| # Function epilogue.
0x236: | Done:
0x236: 90 | ret
| ##################################################################
| # Keep the following label at the end of your function
0x237: | End:
| #/* $end ncopy-ys */
|
0x237: | EndFun:
|
| ###############################
| # Source and destination blocks
| ###############################
0x238: | .align 8
0x238: | src:
0x238: ffffffffffffffff | .quad -1
0x240: 0200000000000000 | .quad 2
0x248: 0300000000000000 | .quad 3
0x250: 0400000000000000 | .quad 4
0x258: 0500000000000000 | .quad 5
0x260: faffffffffffffff | .quad -6
0x268: 0700000000000000 | .quad 7
0x270: f8ffffffffffffff | .quad -8
0x278: 0900000000000000 | .quad 9
0x280: 0a00000000000000 | .quad 10
0x288: 0b00000000000000 | .quad 11
0x290: 0c00000000000000 | .quad 12
0x298: f3ffffffffffffff | .quad -13
0x2a0: 0e00000000000000 | .quad 14
0x2a8: f1ffffffffffffff | .quad -15
0x2b0: 1000000000000000 | .quad 16
0x2b8: efffffffffffffff | .quad -17
0x2c0: 1200000000000000 | .quad 18
0x2c8: 1300000000000000 | .quad 19
0x2d0: 1400000000000000 | .quad 20
0x2d8: ebffffffffffffff | .quad -21
0x2e0: eaffffffffffffff | .quad -22
0x2e8: e9ffffffffffffff | .quad -23
0x2f0: 1800000000000000 | .quad 24
0x2f8: e7ffffffffffffff | .quad -25
0x300: e6ffffffffffffff | .quad -26
0x308: 1b00000000000000 | .quad 27
0x310: e4ffffffffffffff | .quad -28
0x318: e3ffffffffffffff | .quad -29
0x320: e2ffffffffffffff | .quad -30
0x328: 1f00000000000000 | .quad 31
0x330: 2000000000000000 | .quad 32
0x338: 2100000000000000 | .quad 33
0x340: 2200000000000000 | .quad 34
0x348: ddffffffffffffff | .quad -35
0x350: 2400000000000000 | .quad 36
0x358: dbffffffffffffff | .quad -37
0x360: 2600000000000000 | .quad 38
0x368: d9ffffffffffffff | .quad -39
0x370: d8ffffffffffffff | .quad -40
0x378: d7ffffffffffffff | .quad -41
0x380: d6ffffffffffffff | .quad -42
0x388: d5ffffffffffffff | .quad -43
0x390: d4ffffffffffffff | .quad -44
0x398: d3ffffffffffffff | .quad -45
0x3a0: 2e00000000000000 | .quad 46
0x3a8: d1ffffffffffffff | .quad -47
0x3b0: d0ffffffffffffff | .quad -48
0x3b8: cfffffffffffffff | .quad -49
0x3c0: 3200000000000000 | .quad 50
0x3c8: cdffffffffffffff | .quad -51
0x3d0: 3400000000000000 | .quad 52
0x3d8: cbffffffffffffff | .quad -53
0x3e0: 3600000000000000 | .quad 54
0x3e8: c9ffffffffffffff | .quad -55
0x3f0: 3800000000000000 | .quad 56
0x3f8: c7ffffffffffffff | .quad -57
0x400: c6ffffffffffffff | .quad -58
0x408: c5ffffffffffffff | .quad -59
0x410: 3c00000000000000 | .quad 60
0x418: 3d00000000000000 | .quad 61
0x420: 3e00000000000000 | .quad 62
0x428: 3f00000000000000 | .quad 63
0x430: fadebc0000000000 | .quad 0xbcdefa # This shouldn't get moved
|
0x440: | .align 16
0x440: | Predest:
0x440: fadebc0000000000 | .quad 0xbcdefa
0x448: | dest:
0x448: abefcd0000000000 | .quad 0xcdefab
0x450: abefcd0000000000 | .quad 0xcdefab
0x458: abefcd0000000000 | .quad 0xcdefab
0x460: abefcd0000000000 | .quad 0xcdefab
0x468: abefcd0000000000 | .quad 0xcdefab
0x470: abefcd0000000000 | .quad 0xcdefab
0x478: abefcd0000000000 | .quad 0xcdefab
0x480: abefcd0000000000 | .quad 0xcdefab
0x488: abefcd0000000000 | .quad 0xcdefab
0x490: abefcd0000000000 | .quad 0xcdefab
0x498: abefcd0000000000 | .quad 0xcdefab
0x4a0: abefcd0000000000 | .quad 0xcdefab
0x4a8: abefcd0000000000 | .quad 0xcdefab
0x4b0: abefcd0000000000 | .quad 0xcdefab
0x4b8: abefcd0000000000 | .quad 0xcdefab
0x4c0: abefcd0000000000 | .quad 0xcdefab
0x4c8: abefcd0000000000 | .quad 0xcdefab
0x4d0: abefcd0000000000 | .quad 0xcdefab
0x4d8: abefcd0000000000 | .quad 0xcdefab
0x4e0: abefcd0000000000 | .quad 0xcdefab
0x4e8: abefcd0000000000 | .quad 0xcdefab
0x4f0: abefcd0000000000 | .quad 0xcdefab
0x4f8: abefcd0000000000 | .quad 0xcdefab
0x500: abefcd0000000000 | .quad 0xcdefab
0x508: abefcd0000000000 | .quad 0xcdefab
0x510: abefcd0000000000 | .quad 0xcdefab
0x518: abefcd0000000000 | .quad 0xcdefab
0x520: abefcd0000000000 | .quad 0xcdefab
0x528: abefcd0000000000 | .quad 0xcdefab
0x530: abefcd0000000000 | .quad 0xcdefab
0x538: abefcd0000000000 | .quad 0xcdefab
0x540: abefcd0000000000 | .quad 0xcdefab
0x548: abefcd0000000000 | .quad 0xcdefab
0x550: abefcd0000000000 | .quad 0xcdefab
0x558: abefcd0000000000 | .quad 0xcdefab
0x560: abefcd0000000000 | .quad 0xcdefab
0x568: abefcd0000000000 | .quad 0xcdefab
0x570: abefcd0000000000 | .quad 0xcdefab
0x578: abefcd0000000000 | .quad 0xcdefab
0x580: abefcd0000000000 | .quad 0xcdefab
0x588: abefcd0000000000 | .quad 0xcdefab
0x590: abefcd0000000000 | .quad 0xcdefab
0x598: abefcd0000000000 | .quad 0xcdefab
0x5a0: abefcd0000000000 | .quad 0xcdefab
0x5a8: abefcd0000000000 | .quad 0xcdefab
0x5b0: abefcd0000000000 | .quad 0xcdefab
0x5b8: abefcd0000000000 | .quad 0xcdefab
0x5c0: abefcd0000000000 | .quad 0xcdefab
0x5c8: abefcd0000000000 | .quad 0xcdefab
0x5d0: abefcd0000000000 | .quad 0xcdefab
0x5d8: abefcd0000000000 | .quad 0xcdefab
0x5e0: abefcd0000000000 | .quad 0xcdefab
0x5e8: abefcd0000000000 | .quad 0xcdefab
0x5f0: abefcd0000000000 | .quad 0xcdefab
0x5f8: abefcd0000000000 | .quad 0xcdefab
0x600: abefcd0000000000 | .quad 0xcdefab
0x608: abefcd0000000000 | .quad 0xcdefab
0x610: abefcd0000000000 | .quad 0xcdefab
0x618: abefcd0000000000 | .quad 0xcdefab
0x620: abefcd0000000000 | .quad 0xcdefab
0x628: abefcd0000000000 | .quad 0xcdefab
0x630: abefcd0000000000 | .quad 0xcdefab
0x638: abefcd0000000000 | .quad 0xcdefab
0x640: | Postdest:
0x640: bcfade0000000000 | .quad 0xdefabc
|
0x648: | .align 8
| # Run time stack
0x648: 0000000000000000 | .quad 0
0x650: 0000000000000000 | .quad 0
0x658: 0000000000000000 | .quad 0
0x660: 0000000000000000 | .quad 0
0x668: 0000000000000000 | .quad 0
0x670: 0000000000000000 | .quad 0
0x678: 0000000000000000 | .quad 0
0x680: 0000000000000000 | .quad 0
0x688: 0000000000000000 | .quad 0
0x690: 0000000000000000 | .quad 0
0x698: 0000000000000000 | .quad 0
0x6a0: 0000000000000000 | .quad 0
0x6a8: 0000000000000000 | .quad 0
0x6b0: 0000000000000000 | .quad 0
0x6b8: 0000000000000000 | .quad 0
0x6c0: 0000000000000000 | .quad 0
|
0x6c8: | Stack:

View file

@ -0,0 +1,292 @@
#######################################################################
# Test for copying block of size 63;
#######################################################################
.pos 0
main: irmovq Stack, %rsp # Set up stack pointer
# Set up arguments for copy function and then invoke it
irmovq $63, %rdx # src and dst have 63 elements
irmovq dest, %rsi # dst array
irmovq src, %rdi # src array
call ncopy
halt # should halt with num nonzeros in %rax
StartFun:
#/* $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.
# Michael Zhang <zhan4854@umn.edu>
#
# Firstly, I made use of iaddq, in order to prevent having to store
# constants into memory in order to add them. This reduces the number
# of instructions required for incrementing counters. This got my
# CPE down to about 12.7.
#
# I also used the loop unrolling technique to unroll the loop 5
# times. Because it was easy to use jle to compare to 0, I kept
# processing 5 elements at a time until I got to the last 4, at
# which point the counter would go negative. Then I would manually
# add back and execute the instructions 1-by-1 (since there are
# only at most 4 left).
#
##################################################################
# 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:
iaddq $-5, %rdx # Check if it goes negative
jl Last4
MainLoop:
mrmovq (%rdi), %r8
mrmovq 8(%rdi), %r9
mrmovq 16(%rdi), %r10
mrmovq 24(%rdi), %r11
mrmovq 32(%rdi), %r12
rmmovq %r8, (%rsi)
rmmovq %r9, 8(%rsi)
rmmovq %r10, 16(%rsi)
rmmovq %r11, 24(%rsi)
rmmovq %r12, 32(%rsi)
andq %r8, %r8
jle N2
iaddq $1, %rax
N2:
andq %r9, %r9
jle N3
iaddq $1, %rax
N3:
andq %r10, %r10
jle N4
iaddq $1, %rax
N4:
andq %r11, %r11
jle N5
iaddq $1, %rax
N5:
andq %r12, %r12
jle Final
iaddq $1, %rax
Final:
iaddq $40, %rdi
iaddq $40, %rsi
iaddq $-5, %rdx
jge MainLoop
Last4:
iaddq $4, %rdx # Restore from negative
jl Done
mrmovq (%rdi), %r8
rmmovq %r8, (%rsi)
andq %r8, %r8
jle Last3
iaddq $1, %rax
Last3:
iaddq $-1, %rdx
jl Done
mrmovq 8(%rdi), %r8
rmmovq %r8, 8(%rsi)
andq %r8, %r8
jle Last2
iaddq $1, %rax
Last2:
iaddq $-1, %rdx
jl Done
mrmovq 16(%rdi), %r8
rmmovq %r8, 16(%rsi)
andq %r8, %r8
jle Last1
iaddq $1, %rax
Last1:
iaddq $-1, %rdx
jl Done
mrmovq 24(%rdi), %r8
rmmovq %r8, 24(%rsi)
andq %r8, %r8
jle Done
iaddq $1, %rax
##################################################################
# 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 */
EndFun:
###############################
# Source and destination blocks
###############################
.align 8
src:
.quad -1
.quad 2
.quad 3
.quad 4
.quad 5
.quad -6
.quad 7
.quad -8
.quad 9
.quad 10
.quad 11
.quad 12
.quad -13
.quad 14
.quad -15
.quad 16
.quad -17
.quad 18
.quad 19
.quad 20
.quad -21
.quad -22
.quad -23
.quad 24
.quad -25
.quad -26
.quad 27
.quad -28
.quad -29
.quad -30
.quad 31
.quad 32
.quad 33
.quad 34
.quad -35
.quad 36
.quad -37
.quad 38
.quad -39
.quad -40
.quad -41
.quad -42
.quad -43
.quad -44
.quad -45
.quad 46
.quad -47
.quad -48
.quad -49
.quad 50
.quad -51
.quad 52
.quad -53
.quad 54
.quad -55
.quad 56
.quad -57
.quad -58
.quad -59
.quad 60
.quad 61
.quad 62
.quad 63
.quad 0xbcdefa # This shouldn't get moved
.align 16
Predest:
.quad 0xbcdefa
dest:
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
Postdest:
.quad 0xdefabc
.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:

View file

@ -0,0 +1,44 @@
#/* $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:
iaddq $1, %rax # count++
Npos:
iaddq $-1, %rdx # len--
iaddq $8, %rdi # src++
iaddq $8, %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 */

View file

@ -0,0 +1,71 @@
# Saumik Narayanan
# naray114@umn.edu
# 4815779
#/* $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:
iaddq $-2,%rdx
jl len_cleanup
Loop:
mrmovq (%rdi), %r8 # read val from src[0]...
mrmovq 8(%rdi), %r9 # read val from src[1]...
rmmovq %r8, (%rsi) # ...and store it to dst[0]
rmmovq %r9, 8(%rsi) # ...and store it to dst[1]
andq %r8, %r8 # val <= 0?
jle Skip1 # if so, goto Skip1:
iaddq $1, %rax # count++
Skip1:
andq %r9,%r9 # src[1] <= 0?
jle Skip2 # if so, goto Loop:
iaddq $1,%rax # count++
Skip2:
iaddq $16, %rdi # *src+=2
iaddq $16, %rsi # *dst+=2
iaddq $-2, %rdx # len-=2
jge Loop # if len >= 2, goto Loop
len_cleanup:
iaddq $2, %rdx
cleanup:
iaddq $-1,%rdx # len--
jl Done # if len < 0, nothing to cleanup
mrmovq (%rdi),%r8 # read val from src[0]
rmmovq %r8, (%rsi) # store val from src[0] to dst[0]
andq %r8,%r8 # val <= 0?
jle Done # if so, skip count++
iaddq $1,%rax # count++
##################################################################
# 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 */

View file

@ -0,0 +1,39 @@
#include <stdio.h>
typedef word_t word_t;
word_t src[8], dst[8];
/* $begin ncopy */
/*
* ncopy - copy src to dst, returning number of negative 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);
}

View file

@ -0,0 +1,117 @@
#/* $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.
# Michael Zhang <zhan4854@umn.edu>
#
# Firstly, I made use of iaddq, in order to prevent having to store
# constants into memory in order to add them. This reduces the number
# of instructions required for incrementing counters. This got my
# CPE down to about 12.7.
#
# I also used the loop unrolling technique to unroll the loop 5
# times. Because it was easy to use jle to compare to 0, I kept
# processing 5 elements at a time until I got to the last 4, at
# which point the counter would go negative. Then I would manually
# add back and execute the instructions 1-by-1 (since there are
# only at most 4 left).
#
##################################################################
# 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:
iaddq $-5, %rdx # Check if it goes negative
jl Last4
MainLoop:
mrmovq (%rdi), %r8
mrmovq 8(%rdi), %r9
mrmovq 16(%rdi), %r10
mrmovq 24(%rdi), %r11
mrmovq 32(%rdi), %r12
rmmovq %r8, (%rsi)
rmmovq %r9, 8(%rsi)
rmmovq %r10, 16(%rsi)
rmmovq %r11, 24(%rsi)
rmmovq %r12, 32(%rsi)
andq %r8, %r8
jle N2
iaddq $1, %rax
N2:
andq %r9, %r9
jle N3
iaddq $1, %rax
N3:
andq %r10, %r10
jle N4
iaddq $1, %rax
N4:
andq %r11, %r11
jle N5
iaddq $1, %rax
N5:
andq %r12, %r12
jle Final
iaddq $1, %rax
Final:
iaddq $40, %rdi
iaddq $40, %rsi
iaddq $-5, %rdx
jge MainLoop
Last4:
iaddq $4, %rdx # Restore from negative
jl Done
mrmovq (%rdi), %r8
rmmovq %r8, (%rsi)
andq %r8, %r8
jle Last3
iaddq $1, %rax
Last3:
iaddq $-1, %rdx
jl Done
mrmovq 8(%rdi), %r8
rmmovq %r8, 8(%rsi)
andq %r8, %r8
jle Last2
iaddq $1, %rax
Last2:
iaddq $-1, %rdx
jl Done
mrmovq 16(%rdi), %r8
rmmovq %r8, 16(%rsi)
andq %r8, %r8
jle Last1
iaddq $1, %rax
Last1:
iaddq $-1, %rdx
jl Done
mrmovq 24(%rdi), %r8
rmmovq %r8, 24(%rsi)
andq %r8, %r8
jle Done
iaddq $1, %rax
##################################################################
# 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 */

View file

@ -0,0 +1,293 @@
char simname[] = "Y86-64 Processor: pipe-full.hcl";
#include <stdio.h>
#include "isa.h"
#include "pipeline.h"
#include "stages.h"
#include "sim.h"
int sim_main(int argc, char *argv[]);
int main(int argc, char *argv[]){return sim_main(argc,argv);}
long long gen_f_pc()
{
return ((((ex_mem_curr->icode) == (I_JMP)) & !(ex_mem_curr->takebranch)
) ? (ex_mem_curr->vala) : ((mem_wb_curr->icode) == (I_RET)) ?
(mem_wb_curr->valm) : (pc_curr->pc));
}
long long gen_f_icode()
{
return ((imem_error) ? (I_NOP) : (imem_icode));
}
long long gen_f_ifun()
{
return ((imem_error) ? (F_NONE) : (imem_ifun));
}
long long gen_instr_valid()
{
return ((if_id_next->icode) == (I_NOP) || (if_id_next->icode) ==
(I_HALT) || (if_id_next->icode) == (I_RRMOVQ) || (if_id_next->icode)
== (I_IRMOVQ) || (if_id_next->icode) == (I_RMMOVQ) ||
(if_id_next->icode) == (I_MRMOVQ) || (if_id_next->icode) == (I_ALU)
|| (if_id_next->icode) == (I_JMP) || (if_id_next->icode) == (I_CALL)
|| (if_id_next->icode) == (I_RET) || (if_id_next->icode) ==
(I_PUSHQ) || (if_id_next->icode) == (I_POPQ) || (if_id_next->icode)
== (I_IADDQ));
}
long long gen_f_stat()
{
return ((imem_error) ? (STAT_ADR) : !(instr_valid) ? (STAT_INS) : (
(if_id_next->icode) == (I_HALT)) ? (STAT_HLT) : (STAT_AOK));
}
long long gen_need_regids()
{
return ((if_id_next->icode) == (I_RRMOVQ) || (if_id_next->icode) ==
(I_ALU) || (if_id_next->icode) == (I_PUSHQ) || (if_id_next->icode)
== (I_POPQ) || (if_id_next->icode) == (I_IRMOVQ) ||
(if_id_next->icode) == (I_RMMOVQ) || (if_id_next->icode) ==
(I_MRMOVQ) || (if_id_next->icode) == (I_IADDQ));
}
long long gen_need_valC()
{
return ((if_id_next->icode) == (I_IRMOVQ) || (if_id_next->icode) ==
(I_RMMOVQ) || (if_id_next->icode) == (I_MRMOVQ) ||
(if_id_next->icode) == (I_JMP) || (if_id_next->icode) == (I_CALL) ||
(if_id_next->icode) == (I_IADDQ));
}
long long gen_f_predPC()
{
return (((if_id_next->icode) == (I_JMP) || (if_id_next->icode) ==
(I_CALL)) ? (if_id_next->valc) : (if_id_next->valp));
}
long long gen_d_srcA()
{
return (((if_id_curr->icode) == (I_RRMOVQ) || (if_id_curr->icode) ==
(I_RMMOVQ) || (if_id_curr->icode) == (I_ALU) || (if_id_curr->icode)
== (I_PUSHQ)) ? (if_id_curr->ra) : ((if_id_curr->icode) ==
(I_POPQ) || (if_id_curr->icode) == (I_RET)) ? (REG_RSP) :
(REG_NONE));
}
long long gen_d_srcB()
{
return (((if_id_curr->icode) == (I_ALU) || (if_id_curr->icode) ==
(I_RMMOVQ) || (if_id_curr->icode) == (I_MRMOVQ) ||
(if_id_curr->icode) == (I_IADDQ)) ? (if_id_curr->rb) : (
(if_id_curr->icode) == (I_PUSHQ) || (if_id_curr->icode) == (I_POPQ)
|| (if_id_curr->icode) == (I_CALL) || (if_id_curr->icode) ==
(I_RET)) ? (REG_RSP) : (REG_NONE));
}
long long gen_d_dstE()
{
return (((if_id_curr->icode) == (I_RRMOVQ) || (if_id_curr->icode) ==
(I_IRMOVQ) || (if_id_curr->icode) == (I_ALU) || (if_id_curr->icode)
== (I_IADDQ)) ? (if_id_curr->rb) : ((if_id_curr->icode) ==
(I_PUSHQ) || (if_id_curr->icode) == (I_POPQ) || (if_id_curr->icode)
== (I_CALL) || (if_id_curr->icode) == (I_RET)) ? (REG_RSP) :
(REG_NONE));
}
long long gen_d_dstM()
{
return (((if_id_curr->icode) == (I_MRMOVQ) || (if_id_curr->icode) ==
(I_POPQ)) ? (if_id_curr->ra) : (REG_NONE));
}
long long gen_d_valA()
{
return (((if_id_curr->icode) == (I_CALL) || (if_id_curr->icode) ==
(I_JMP)) ? (if_id_curr->valp) : ((id_ex_next->srca) ==
(ex_mem_next->deste)) ? (ex_mem_next->vale) : ((id_ex_next->srca)
== (ex_mem_curr->destm)) ? (mem_wb_next->valm) : (
(id_ex_next->srca) == (ex_mem_curr->deste)) ? (ex_mem_curr->vale)
: ((id_ex_next->srca) == (mem_wb_curr->destm)) ? (mem_wb_curr->valm)
: ((id_ex_next->srca) == (mem_wb_curr->deste)) ? (mem_wb_curr->vale)
: (d_regvala));
}
long long gen_d_valB()
{
return (((id_ex_next->srcb) == (ex_mem_next->deste)) ?
(ex_mem_next->vale) : ((id_ex_next->srcb) == (ex_mem_curr->destm)) ?
(mem_wb_next->valm) : ((id_ex_next->srcb) == (ex_mem_curr->deste)) ?
(ex_mem_curr->vale) : ((id_ex_next->srcb) == (mem_wb_curr->destm)) ?
(mem_wb_curr->valm) : ((id_ex_next->srcb) == (mem_wb_curr->deste)) ?
(mem_wb_curr->vale) : (d_regvalb));
}
long long gen_aluA()
{
return (((id_ex_curr->icode) == (I_RRMOVQ) || (id_ex_curr->icode) ==
(I_ALU)) ? (id_ex_curr->vala) : ((id_ex_curr->icode) == (I_IRMOVQ)
|| (id_ex_curr->icode) == (I_RMMOVQ) || (id_ex_curr->icode) ==
(I_MRMOVQ) || (id_ex_curr->icode) == (I_IRMOVQ) ||
(id_ex_curr->icode) == (I_IADDQ)) ? (id_ex_curr->valc) : (
(id_ex_curr->icode) == (I_CALL) || (id_ex_curr->icode) == (I_PUSHQ)
) ? -8 : ((id_ex_curr->icode) == (I_RET) || (id_ex_curr->icode) ==
(I_POPQ)) ? 8 : 0);
}
long long gen_aluB()
{
return (((id_ex_curr->icode) == (I_RMMOVQ) || (id_ex_curr->icode) ==
(I_MRMOVQ) || (id_ex_curr->icode) == (I_ALU) || (id_ex_curr->icode)
== (I_CALL) || (id_ex_curr->icode) == (I_PUSHQ) ||
(id_ex_curr->icode) == (I_RET) || (id_ex_curr->icode) == (I_POPQ)
|| (id_ex_curr->icode) == (I_IADDQ)) ? (id_ex_curr->valb) : (
(id_ex_curr->icode) == (I_RRMOVQ) || (id_ex_curr->icode) ==
(I_IRMOVQ)) ? 0 : 0);
}
long long gen_alufun()
{
return (((id_ex_curr->icode) == (I_ALU)) ? (id_ex_curr->ifun) : (A_ADD)
);
}
long long gen_set_cc()
{
return ((((id_ex_curr->icode) == (I_ALU) || (id_ex_curr->icode) ==
(I_IADDQ)) & !((mem_wb_next->status) == (STAT_ADR) ||
(mem_wb_next->status) == (STAT_INS) || (mem_wb_next->status) ==
(STAT_HLT))) & !((mem_wb_curr->status) == (STAT_ADR) ||
(mem_wb_curr->status) == (STAT_INS) || (mem_wb_curr->status) ==
(STAT_HLT)));
}
long long gen_e_valA()
{
return (id_ex_curr->vala);
}
long long gen_e_dstE()
{
return ((((id_ex_curr->icode) == (I_RRMOVQ)) & !
(ex_mem_next->takebranch)) ? (REG_NONE) : (id_ex_curr->deste));
}
long long gen_mem_addr()
{
return (((ex_mem_curr->icode) == (I_RMMOVQ) || (ex_mem_curr->icode) ==
(I_PUSHQ) || (ex_mem_curr->icode) == (I_CALL) ||
(ex_mem_curr->icode) == (I_MRMOVQ)) ? (ex_mem_curr->vale) : (
(ex_mem_curr->icode) == (I_POPQ) || (ex_mem_curr->icode) == (I_RET)
) ? (ex_mem_curr->vala) : 0);
}
long long gen_mem_read()
{
return ((ex_mem_curr->icode) == (I_MRMOVQ) || (ex_mem_curr->icode) ==
(I_POPQ) || (ex_mem_curr->icode) == (I_RET));
}
long long gen_mem_write()
{
return ((ex_mem_curr->icode) == (I_RMMOVQ) || (ex_mem_curr->icode) ==
(I_PUSHQ) || (ex_mem_curr->icode) == (I_CALL));
}
long long gen_m_stat()
{
return ((dmem_error) ? (STAT_ADR) : (ex_mem_curr->status));
}
long long gen_w_dstE()
{
return (mem_wb_curr->deste);
}
long long gen_w_valE()
{
return (mem_wb_curr->vale);
}
long long gen_w_dstM()
{
return (mem_wb_curr->destm);
}
long long gen_w_valM()
{
return (mem_wb_curr->valm);
}
long long gen_Stat()
{
return (((mem_wb_curr->status) == (STAT_BUB)) ? (STAT_AOK) :
(mem_wb_curr->status));
}
long long gen_F_bubble()
{
return 0;
}
long long gen_F_stall()
{
return ((((id_ex_curr->icode) == (I_MRMOVQ) || (id_ex_curr->icode) ==
(I_POPQ)) & ((id_ex_curr->destm) == (id_ex_next->srca) ||
(id_ex_curr->destm) == (id_ex_next->srcb))) | ((I_RET) ==
(if_id_curr->icode) || (I_RET) == (id_ex_curr->icode) || (I_RET)
== (ex_mem_curr->icode)));
}
long long gen_D_stall()
{
return (((id_ex_curr->icode) == (I_MRMOVQ) || (id_ex_curr->icode) ==
(I_POPQ)) & ((id_ex_curr->destm) == (id_ex_next->srca) ||
(id_ex_curr->destm) == (id_ex_next->srcb)));
}
long long gen_D_bubble()
{
return ((((id_ex_curr->icode) == (I_JMP)) & !(ex_mem_next->takebranch))
| (!(((id_ex_curr->icode) == (I_MRMOVQ) || (id_ex_curr->icode) ==
(I_POPQ)) & ((id_ex_curr->destm) == (id_ex_next->srca) ||
(id_ex_curr->destm) == (id_ex_next->srcb))) & ((I_RET) ==
(if_id_curr->icode) || (I_RET) == (id_ex_curr->icode) || (I_RET)
== (ex_mem_curr->icode))));
}
long long gen_E_stall()
{
return 0;
}
long long gen_E_bubble()
{
return ((((id_ex_curr->icode) == (I_JMP)) & !(ex_mem_next->takebranch))
| (((id_ex_curr->icode) == (I_MRMOVQ) || (id_ex_curr->icode) ==
(I_POPQ)) & ((id_ex_curr->destm) == (id_ex_next->srca) ||
(id_ex_curr->destm) == (id_ex_next->srcb))));
}
long long gen_M_stall()
{
return 0;
}
long long gen_M_bubble()
{
return (((mem_wb_next->status) == (STAT_ADR) || (mem_wb_next->status)
== (STAT_INS) || (mem_wb_next->status) == (STAT_HLT)) | (
(mem_wb_curr->status) == (STAT_ADR) || (mem_wb_curr->status) ==
(STAT_INS) || (mem_wb_curr->status) == (STAT_HLT)));
}
long long gen_W_stall()
{
return ((mem_wb_curr->status) == (STAT_ADR) || (mem_wb_curr->status)
== (STAT_INS) || (mem_wb_curr->status) == (STAT_HLT));
}
long long gen_W_bubble()
{
return 0;
}

View file

@ -0,0 +1,390 @@
# Michael Zhang <zhan4854@umn.edu>
# I modified this file in the same way I modified the sequential
# processor, adding iaddq in the same manner. IADDQ just adds a constant
# to a register, without needing to store the constant into a register
# with a irmovq first.
# For reference:
# ----------+-------------------------+
# Stage | iaddq V, rB |
# ----------+-------------------------+
# Fetch | icode:ifun <= M1[PC] |
# | rA:rB <= M1[PC+1] |
# | valC <= M8[PC+2] |
# | valP <= PC+10 |
# ----------+-------------------------+
# Decode | valB <= R[rB] |
# ----------+-------------------------+
# Execute | valE <= valB+valC |
# ----------+-------------------------+
# Memory | n o t h i n g |
# ----------+-------------------------+
# WriteBack | R[rB] <= valE |
# ----------+-------------------------+
# PCUpdate | PC <= valP |
# ----------+-------------------------+
#/* $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, IIADDQ };
# 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, IIADDQ };
# Does fetched instruction require a constant word?
bool need_valC =
f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL, IIADDQ };
# 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, IIADDQ } : 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, IIADDQ } : 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, IIRMOVQ, IIADDQ } : 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, IIADDQ } : 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 in { IOPQ, IIADDQ } &&
# 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 */

View file

@ -0,0 +1,633 @@
##########################################################################
# 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}

View file

@ -0,0 +1,67 @@
/******************************************************************************
* 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 */

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,174 @@
| #######################################################################
| # Test for copying block of size 4;
| #######################################################################
0x000: | .pos 0
0x000: 30f41003000000000000 | main: irmovq Stack, %rsp # Set up stack pointer
|
| # Set up arguments for copy function and then invoke it
0x00a: 30f20400000000000000 | irmovq $4, %rdx # src and dst have 4 elements
0x014: 30f66802000000000000 | irmovq dest, %rsi # dst array
0x01e: 30f73802000000000000 | irmovq src, %rdi # src array
0x028: 803200000000000000 | call ncopy
0x031: 00 | halt # should halt with num nonzeros in %rax
0x032: | StartFun:
| #/* $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.
| # Michael Zhang <zhan4854@umn.edu>
| #
| # Firstly, I made use of iaddq, in order to prevent having to store
| # constants into memory in order to add them. This reduces the number
| # of instructions required for incrementing counters. This got my
| # CPE down to about 12.7.
| #
| # I also used the loop unrolling technique to unroll the loop 5
| # times. Because it was easy to use jle to compare to 0, I kept
| # processing 5 elements at a time until I got to the last 4, at
| # which point the counter would go negative. Then I would manually
| # add back and execute the instructions 1-by-1 (since there are
| # only at most 4 left).
| #
| ##################################################################
| # Do not modify this portion
| # Function prologue.
| # %rdi = src, %rsi = dst, %rdx = len
0x032: | ncopy:
|
| ##################################################################
| # You can modify this portion
| # Loop header
0x032: 6300 | xorq %rax,%rax # count = 0;
0x034: 6222 | andq %rdx,%rdx # len <= 0?
0x036: 713602000000000000 | jle Done # if so, goto Done:
0x03f: c0f2fbffffffffffffff | iaddq $-5, %rdx # Check if it goes negative
0x049: 724601000000000000 | jl Last4
|
0x052: | MainLoop:
0x052: 50870000000000000000 | mrmovq (%rdi), %r8
0x05c: 50970800000000000000 | mrmovq 8(%rdi), %r9
0x066: 50a71000000000000000 | mrmovq 16(%rdi), %r10
0x070: 50b71800000000000000 | mrmovq 24(%rdi), %r11
0x07a: 50c72000000000000000 | mrmovq 32(%rdi), %r12
|
0x084: 40860000000000000000 | rmmovq %r8, (%rsi)
0x08e: 40960800000000000000 | rmmovq %r9, 8(%rsi)
0x098: 40a61000000000000000 | rmmovq %r10, 16(%rsi)
0x0a2: 40b61800000000000000 | rmmovq %r11, 24(%rsi)
0x0ac: 40c62000000000000000 | rmmovq %r12, 32(%rsi)
|
0x0b6: 6288 | andq %r8, %r8
0x0b8: 71cb00000000000000 | jle N2
0x0c1: c0f00100000000000000 | iaddq $1, %rax
0x0cb: | N2:
0x0cb: 6299 | andq %r9, %r9
0x0cd: 71e000000000000000 | jle N3
0x0d6: c0f00100000000000000 | iaddq $1, %rax
0x0e0: | N3:
0x0e0: 62aa | andq %r10, %r10
0x0e2: 71f500000000000000 | jle N4
0x0eb: c0f00100000000000000 | iaddq $1, %rax
0x0f5: | N4:
0x0f5: 62bb | andq %r11, %r11
0x0f7: 710a01000000000000 | jle N5
0x100: c0f00100000000000000 | iaddq $1, %rax
0x10a: | N5:
0x10a: 62cc | andq %r12, %r12
0x10c: 711f01000000000000 | jle Final
0x115: c0f00100000000000000 | iaddq $1, %rax
|
0x11f: | Final:
0x11f: c0f72800000000000000 | iaddq $40, %rdi
0x129: c0f62800000000000000 | iaddq $40, %rsi
0x133: c0f2fbffffffffffffff | iaddq $-5, %rdx
0x13d: 755200000000000000 | jge MainLoop
|
0x146: | Last4:
0x146: c0f20400000000000000 | iaddq $4, %rdx # Restore from negative
0x150: 723602000000000000 | jl Done
0x159: 50870000000000000000 | mrmovq (%rdi), %r8
0x163: 40860000000000000000 | rmmovq %r8, (%rsi)
0x16d: 6288 | andq %r8, %r8
0x16f: 718201000000000000 | jle Last3
0x178: c0f00100000000000000 | iaddq $1, %rax
0x182: | Last3:
0x182: c0f2ffffffffffffffff | iaddq $-1, %rdx
0x18c: 723602000000000000 | jl Done
0x195: 50870800000000000000 | mrmovq 8(%rdi), %r8
0x19f: 40860800000000000000 | rmmovq %r8, 8(%rsi)
0x1a9: 6288 | andq %r8, %r8
0x1ab: 71be01000000000000 | jle Last2
0x1b4: c0f00100000000000000 | iaddq $1, %rax
0x1be: | Last2:
0x1be: c0f2ffffffffffffffff | iaddq $-1, %rdx
0x1c8: 723602000000000000 | jl Done
0x1d1: 50871000000000000000 | mrmovq 16(%rdi), %r8
0x1db: 40861000000000000000 | rmmovq %r8, 16(%rsi)
0x1e5: 6288 | andq %r8, %r8
0x1e7: 71fa01000000000000 | jle Last1
0x1f0: c0f00100000000000000 | iaddq $1, %rax
0x1fa: | Last1:
0x1fa: c0f2ffffffffffffffff | iaddq $-1, %rdx
0x204: 723602000000000000 | jl Done
0x20d: 50871800000000000000 | mrmovq 24(%rdi), %r8
0x217: 40861800000000000000 | rmmovq %r8, 24(%rsi)
0x221: 6288 | andq %r8, %r8
0x223: 713602000000000000 | jle Done
0x22c: c0f00100000000000000 | iaddq $1, %rax
|
| ##################################################################
| # Do not modify the following section of code
| # Function epilogue.
0x236: | Done:
0x236: 90 | ret
| ##################################################################
| # Keep the following label at the end of your function
0x237: | End:
| #/* $end ncopy-ys */
|
0x237: | EndFun:
|
| ###############################
| # Source and destination blocks
| ###############################
0x238: | .align 8
0x238: | src:
0x238: 0100000000000000 | .quad 1
0x240: 0200000000000000 | .quad 2
0x248: fdffffffffffffff | .quad -3
0x250: fcffffffffffffff | .quad -4
0x258: fadebc0000000000 | .quad 0xbcdefa # This shouldn't get moved
|
0x260: | .align 16
0x260: | Predest:
0x260: fadebc0000000000 | .quad 0xbcdefa
0x268: | dest:
0x268: abefcd0000000000 | .quad 0xcdefab
0x270: abefcd0000000000 | .quad 0xcdefab
0x278: abefcd0000000000 | .quad 0xcdefab
0x280: abefcd0000000000 | .quad 0xcdefab
0x288: | Postdest:
0x288: bcfade0000000000 | .quad 0xdefabc
|
0x290: | .align 8
| # Run time stack
0x290: 0000000000000000 | .quad 0
0x298: 0000000000000000 | .quad 0
0x2a0: 0000000000000000 | .quad 0
0x2a8: 0000000000000000 | .quad 0
0x2b0: 0000000000000000 | .quad 0
0x2b8: 0000000000000000 | .quad 0
0x2c0: 0000000000000000 | .quad 0
0x2c8: 0000000000000000 | .quad 0
0x2d0: 0000000000000000 | .quad 0
0x2d8: 0000000000000000 | .quad 0
0x2e0: 0000000000000000 | .quad 0
0x2e8: 0000000000000000 | .quad 0
0x2f0: 0000000000000000 | .quad 0
0x2f8: 0000000000000000 | .quad 0
0x300: 0000000000000000 | .quad 0
0x308: 0000000000000000 | .quad 0
|
0x310: | Stack:

View file

@ -0,0 +1,174 @@
#######################################################################
# Test for copying block of size 4;
#######################################################################
.pos 0
main: irmovq Stack, %rsp # Set up stack pointer
# Set up arguments for copy function and then invoke it
irmovq $4, %rdx # src and dst have 4 elements
irmovq dest, %rsi # dst array
irmovq src, %rdi # src array
call ncopy
halt # should halt with num nonzeros in %rax
StartFun:
#/* $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.
# Michael Zhang <zhan4854@umn.edu>
#
# Firstly, I made use of iaddq, in order to prevent having to store
# constants into memory in order to add them. This reduces the number
# of instructions required for incrementing counters. This got my
# CPE down to about 12.7.
#
# I also used the loop unrolling technique to unroll the loop 5
# times. Because it was easy to use jle to compare to 0, I kept
# processing 5 elements at a time until I got to the last 4, at
# which point the counter would go negative. Then I would manually
# add back and execute the instructions 1-by-1 (since there are
# only at most 4 left).
#
##################################################################
# 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:
iaddq $-5, %rdx # Check if it goes negative
jl Last4
MainLoop:
mrmovq (%rdi), %r8
mrmovq 8(%rdi), %r9
mrmovq 16(%rdi), %r10
mrmovq 24(%rdi), %r11
mrmovq 32(%rdi), %r12
rmmovq %r8, (%rsi)
rmmovq %r9, 8(%rsi)
rmmovq %r10, 16(%rsi)
rmmovq %r11, 24(%rsi)
rmmovq %r12, 32(%rsi)
andq %r8, %r8
jle N2
iaddq $1, %rax
N2:
andq %r9, %r9
jle N3
iaddq $1, %rax
N3:
andq %r10, %r10
jle N4
iaddq $1, %rax
N4:
andq %r11, %r11
jle N5
iaddq $1, %rax
N5:
andq %r12, %r12
jle Final
iaddq $1, %rax
Final:
iaddq $40, %rdi
iaddq $40, %rsi
iaddq $-5, %rdx
jge MainLoop
Last4:
iaddq $4, %rdx # Restore from negative
jl Done
mrmovq (%rdi), %r8
rmmovq %r8, (%rsi)
andq %r8, %r8
jle Last3
iaddq $1, %rax
Last3:
iaddq $-1, %rdx
jl Done
mrmovq 8(%rdi), %r8
rmmovq %r8, 8(%rsi)
andq %r8, %r8
jle Last2
iaddq $1, %rax
Last2:
iaddq $-1, %rdx
jl Done
mrmovq 16(%rdi), %r8
rmmovq %r8, 16(%rsi)
andq %r8, %r8
jle Last1
iaddq $1, %rax
Last1:
iaddq $-1, %rdx
jl Done
mrmovq 24(%rdi), %r8
rmmovq %r8, 24(%rsi)
andq %r8, %r8
jle Done
iaddq $1, %rax
##################################################################
# 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 */
EndFun:
###############################
# Source and destination blocks
###############################
.align 8
src:
.quad 1
.quad 2
.quad -3
.quad -4
.quad 0xbcdefa # This shouldn't get moved
.align 16
Predest:
.quad 0xbcdefa
dest:
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
.quad 0xcdefab
Postdest:
.quad 0xdefabc
.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:

View file

@ -0,0 +1,153 @@
/********** 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

View file

@ -0,0 +1,90 @@
/*
* 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();

View file

@ -0,0 +1,20 @@
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

View file

@ -0,0 +1,36 @@
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.

View file

@ -0,0 +1,113 @@
#!/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();

View file

@ -0,0 +1,75 @@
#!/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();

View file

@ -0,0 +1,249 @@
#!/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();

View file

@ -0,0 +1,127 @@
#!/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();

View file

@ -0,0 +1,92 @@
#!/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();

View file

@ -0,0 +1,187 @@
# 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;

View file

@ -0,0 +1,65 @@
# Modify this line to indicate the default version
VERSION=full
# 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/tk
# Modify these two lines to choose your compiler and compile time
# flags.
CC=/usr/bin/gcc
CFLAGS=-Wall -O2 -DUSE_INTERP_RESULT
##################################################
# 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

View file

@ -0,0 +1,91 @@
/***********************************************************************
* 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)

View file

@ -0,0 +1,226 @@
#/* $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 */

View file

@ -0,0 +1,540 @@
##########################################################################
# 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 " "%r8 " "%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}

View file

@ -0,0 +1,134 @@
char simname[] = "Y86-64 Processor: seq-full.hcl";
#include <stdio.h>
#include "isa.h"
#include "sim.h"
int sim_main(int argc, char *argv[]);
word_t gen_pc(){return 0;}
int main(int argc, char *argv[])
{plusmode=0;return sim_main(argc,argv);}
long long gen_icode()
{
return ((imem_error) ? (I_NOP) : (imem_icode));
}
long long gen_ifun()
{
return ((imem_error) ? (F_NONE) : (imem_ifun));
}
long long gen_instr_valid()
{
return ((icode) == (I_NOP) || (icode) == (I_HALT) || (icode) ==
(I_RRMOVQ) || (icode) == (I_IRMOVQ) || (icode) == (I_RMMOVQ) ||
(icode) == (I_MRMOVQ) || (icode) == (I_ALU) || (icode) == (I_JMP) ||
(icode) == (I_CALL) || (icode) == (I_RET) || (icode) == (I_PUSHQ) ||
(icode) == (I_POPQ) || (icode) == (I_IADDQ));
}
long long gen_need_regids()
{
return ((icode) == (I_RRMOVQ) || (icode) == (I_ALU) || (icode) ==
(I_PUSHQ) || (icode) == (I_POPQ) || (icode) == (I_IRMOVQ) || (icode)
== (I_RMMOVQ) || (icode) == (I_MRMOVQ) || (icode) == (I_IADDQ));
}
long long gen_need_valC()
{
return ((icode) == (I_IRMOVQ) || (icode) == (I_RMMOVQ) || (icode) ==
(I_MRMOVQ) || (icode) == (I_JMP) || (icode) == (I_CALL) || (icode)
== (I_IADDQ));
}
long long gen_srcA()
{
return (((icode) == (I_RRMOVQ) || (icode) == (I_RMMOVQ) || (icode) ==
(I_ALU) || (icode) == (I_PUSHQ)) ? (ra) : ((icode) == (I_POPQ) ||
(icode) == (I_RET)) ? (REG_RSP) : (REG_NONE));
}
long long gen_srcB()
{
return (((icode) == (I_ALU) || (icode) == (I_RMMOVQ) || (icode) ==
(I_MRMOVQ) || (icode) == (I_IADDQ)) ? (rb) : ((icode) == (I_PUSHQ)
|| (icode) == (I_POPQ) || (icode) == (I_CALL) || (icode) ==
(I_RET)) ? (REG_RSP) : (REG_NONE));
}
long long gen_dstE()
{
return ((((icode) == (I_RRMOVQ)) & (cond)) ? (rb) : ((icode) ==
(I_IRMOVQ) || (icode) == (I_ALU) || (icode) == (I_IADDQ)) ? (rb) :
((icode) == (I_PUSHQ) || (icode) == (I_POPQ) || (icode) == (I_CALL)
|| (icode) == (I_RET)) ? (REG_RSP) : (REG_NONE));
}
long long gen_dstM()
{
return (((icode) == (I_MRMOVQ) || (icode) == (I_POPQ)) ? (ra) :
(REG_NONE));
}
long long gen_aluA()
{
return (((icode) == (I_RRMOVQ) || (icode) == (I_ALU)) ? (vala) : (
(icode) == (I_IRMOVQ) || (icode) == (I_RMMOVQ) || (icode) ==
(I_MRMOVQ) || (icode) == (I_IADDQ)) ? (valc) : ((icode) == (I_CALL)
|| (icode) == (I_PUSHQ)) ? -8 : ((icode) == (I_RET) || (icode) ==
(I_POPQ)) ? 8 : 0);
}
long long gen_aluB()
{
return (((icode) == (I_RMMOVQ) || (icode) == (I_MRMOVQ) || (icode) ==
(I_ALU) || (icode) == (I_CALL) || (icode) == (I_PUSHQ) || (icode)
== (I_RET) || (icode) == (I_POPQ) || (icode) == (I_IADDQ)) ?
(valb) : ((icode) == (I_RRMOVQ) || (icode) == (I_IRMOVQ)) ? 0 : 0);
}
long long gen_alufun()
{
return (((icode) == (I_ALU)) ? (ifun) : (A_ADD));
}
long long gen_set_cc()
{
return ((icode) == (I_ALU) || (icode) == (I_IADDQ));
}
long long gen_mem_read()
{
return ((icode) == (I_MRMOVQ) || (icode) == (I_POPQ) || (icode) ==
(I_RET));
}
long long gen_mem_write()
{
return ((icode) == (I_RMMOVQ) || (icode) == (I_PUSHQ) || (icode) ==
(I_CALL));
}
long long gen_mem_addr()
{
return (((icode) == (I_RMMOVQ) || (icode) == (I_PUSHQ) || (icode) ==
(I_CALL) || (icode) == (I_MRMOVQ)) ? (vale) : ((icode) == (I_POPQ)
|| (icode) == (I_RET)) ? (vala) : 0);
}
long long gen_mem_data()
{
return (((icode) == (I_RMMOVQ) || (icode) == (I_PUSHQ)) ? (vala) : (
(icode) == (I_CALL)) ? (valp) : 0);
}
long long gen_Stat()
{
return (((imem_error) | (dmem_error)) ? (STAT_ADR) : !(instr_valid) ?
(STAT_INS) : ((icode) == (I_HALT)) ? (STAT_HLT) : (STAT_AOK));
}
long long gen_new_pc()
{
return (((icode) == (I_CALL)) ? (valc) : (((icode) == (I_JMP)) & (cond)
) ? (valc) : ((icode) == (I_RET)) ? (valm) : (valp));
}

View file

@ -0,0 +1,249 @@
## Michael Zhang <zhan4854@umn.edu>
# H o w i t w o r k s.jpg
# ----------+-------------------------+
# Stage | iaddq V, rB |
# ----------+-------------------------+
# Fetch | icode:ifun <= M1[PC] |
# | rA:rB <= M1[PC+1] |
# | valC <= M8[PC+2] |
# | valP <= PC+10 |
# ----------+-------------------------+
# Decode | valB <= R[rB] |
# ----------+-------------------------+
# Execute | valE <= valB+valC |
# ----------+-------------------------+
# Memory | n o t h i n g |
# ----------+-------------------------+
# WriteBack | R[rB] <= valE |
# ----------+-------------------------+
# PCUpdate | PC <= valP |
# ----------+-------------------------+
#/* $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, IIADDQ };
# Does fetched instruction require a regid byte?
bool need_regids =
icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ,
IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ };
# Does fetched instruction require a constant word?
bool need_valC =
icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL, IIADDQ };
################ 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, IIADDQ } : 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, IIADDQ } : 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, IIADDQ } : 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, IIADDQ } : 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, IIADDQ };
################ 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 */

View file

@ -0,0 +1,540 @@
##########################################################################
# 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 " "%r8 " "%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}

View file

@ -0,0 +1,108 @@
/********** 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

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
CC=/usr/bin/gcc
CFLAGS=-Wall -O2 -DUSE_INTERP_RESULT
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

View file

@ -0,0 +1,20 @@
This directory contains examples of Y86-64 assembly code programs
(extension `.ys') used in Chapter 4 of CS:APP2e.
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.

View file

@ -0,0 +1,46 @@
| # Modification of asum code to compute absolute values of entries.
| # This version uses a conditional move
| # Execution begins at address 0
0x000: | .pos 0
0x000: 30f40002000000000000 | irmovq stack, %rsp # Set up stack pointer
0x00a: 803800000000000000 | call main # Execute main program
0x013: 00 | halt # Terminate program
|
| # Array of 4 elements
0x018: | .align 8
0x018: 0d000d000d000000 | array: .quad 0x0000000d000d000d
0x020: 40ff3fff3fffffff | .quad 0xffffff3fff3fff40 # -0x000000c000c000c0
0x028: 000b000b000b0000 | .quad 0x00000b000b000b00
0x030: 0060ff5fff5fffff | .quad 0xffff5fff5fff6000 # -0x0000a000a000a000
|
0x038: | main:
0x038: 30f71800000000000000 | irmovq array,%rdi
0x042: 30f60400000000000000 | irmovq $4,%rsi
0x04c: 805600000000000000 | call absSum # absSum(array, 4)
0x055: 90 | ret
|
| # long absSum(long *start, long count)
| # start in %rdi, count in %rsi
0x056: | absSum:
0x056: 30f80800000000000000 | irmovq $8,%r8 # Constant 8
0x060: 30f90100000000000000 | irmovq $1,%r9 # Constant 1
0x06a: 6300 | xorq %rax,%rax # sum = 0
0x06c: 6266 | andq %rsi,%rsi # Set condition codes
0x06e: 708d00000000000000 | jmp test
| /* $begin abs-sum-cmov-ys */
0x077: | loop:
0x077: 50a70000000000000000 | mrmovq (%rdi),%r10 # x = *start
0x081: 63bb | xorq %r11,%r11 # Constant 0
0x083: 61ab | subq %r10,%r11 # -x
0x085: 26ba | cmovg %r11,%r10 # If -x > 0 then x = -x
0x087: 60a0 | addq %r10,%rax # Add to sum
0x089: 6087 | addq %r8,%rdi # start++
0x08b: 6196 | subq %r9,%rsi # count--
0x08d: | test:
0x08d: 747700000000000000 | jne loop # Stop when 0
| /* $end abs-sum-cmov-ys */
0x096: 90 | ret
|
| # The stack starts here and grows to lower addresses
0x200: | .pos 0x200
0x200: | stack:

View file

@ -0,0 +1,46 @@
# 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:

View file

@ -0,0 +1,46 @@
| # Modification of asum code to compute absolute values of entries.
| # This version uses a conditional jump
| # Execution begins at address 0
0x000: | .pos 0
0x000: 30f40002000000000000 | irmovq stack, %rsp # Set up stack pointer
0x00a: 803800000000000000 | call main # Execute main program
0x013: 00 | halt # Terminate program
|
| # Array of 4 elements
0x018: | .align 8
0x018: 0d000d000d000000 | array: .quad 0x0000000d000d000d
0x020: 40ff3fff3fffffff | .quad 0xffffff3fff3fff40 # -0x000000c000c000c0
0x028: 000b000b000b0000 | .quad 0x00000b000b000b00
0x030: 0060ff5fff5fffff | .quad 0xffff5fff5fff6000 # -0x0000a000a000a000
|
0x038: 30f71800000000000000 | main: irmovq array,%rdi
0x042: 30f60400000000000000 | irmovq $4,%rsi
0x04c: 805600000000000000 | call absSum # absSum(array, 4)
0x055: 90 | ret
| /* $begin abs-sum-jmp-ys */
| # long absSum(long *start, long count)
| # start in %rdi, count in %rsi
0x056: | absSum:
0x056: 30f80800000000000000 | irmovq $8,%r8 # Constant 8
0x060: 30f90100000000000000 | irmovq $1,%r9 # Constant 1
0x06a: 6300 | xorq %rax,%rax # sum = 0
0x06c: 6266 | andq %rsi,%rsi # Set condition codes
0x06e: 709600000000000000 | jmp test
0x077: | loop:
0x077: 50a70000000000000000 | mrmovq (%rdi),%r10 # x = *start
0x081: 63bb | xorq %r11,%r11 # Constant 0
0x083: 61ab | subq %r10,%r11 # -x
0x085: 719000000000000000 | jle pos # Skip if -x <= 0
0x08e: 20ba | rrmovq %r11,%r10 # x = -x
0x090: | pos:
0x090: 60a0 | addq %r10,%rax # Add to sum
0x092: 6087 | addq %r8,%rdi # start++
0x094: 6196 | subq %r9,%rsi # count--
0x096: | test:
0x096: 747700000000000000 | jne loop # Stop when 0
0x09f: 90 | ret
| /* $end abs-sum-jmp-ys */
|
| # The stack starts here and grows to lower addresses
0x200: | .pos 0x200
0x200: | stack:

View file

@ -0,0 +1,46 @@
# 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:

View file

@ -0,0 +1,35 @@
| # Execution begins at address 0
0x000: | .pos 0
0x000: 30f40002000000000000 | irmovq stack, %rsp # Set up stack pointer
0x00a: 803800000000000000 | call main # Execute main program
0x013: 00 | halt # Terminate program
|
| # Array of 4 elements
0x018: | .align 8
0x018: 0d000d000d000000 | array: .quad 0x000d000d000d
0x020: c000c000c0000000 | .quad 0x00c000c000c0
0x028: 000b000b000b0000 | .quad 0x0b000b000b00
0x030: 00a000a000a00000 | .quad 0xa000a000a000
|
0x038: 30f71800000000000000 | main: irmovq array,%rdi
0x042: 30f60400000000000000 | irmovq $4,%rsi
0x04c: 805600000000000000 | call sum # sum(array, 4)
0x055: 90 | ret
|
| # long sum(long *start, long count)
| # start in %rdi, count in %rsi
0x056: 30f80800000000000000 | sum: irmovq $8,%r8 # Constant 8
0x060: 30f90100000000000000 | irmovq $1,%r9 # Constant 1
0x06a: 6300 | xorq %rax,%rax # sum = 0
0x06c: 6266 | andq %rsi,%rsi # Set CC
0x06e: 708700000000000000 | jmp test # Goto test
0x077: 50a70000000000000000 | loop: mrmovq (%rdi),%r10 # Get *start
0x081: 60a0 | addq %r10,%rax # Add to sum
0x083: 6087 | addq %r8,%rdi # start++
0x085: 6196 | subq %r9,%rsi # count--. Set CC
0x087: 747700000000000000 | test: jne loop # Stop when 0
0x090: 90 | ret # Return
|
| # Stack starts here and grows to lower addresses
0x200: | .pos 0x200
0x200: | stack:

View file

@ -0,0 +1,35 @@
# 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:

View file

@ -0,0 +1,38 @@
| # Execution begins at address 0
0x000: | .pos 0
0x000: 30f40001000000000000 | irmovq stack, %rsp # Set up stack pointer
0x00a: 803800000000000000 | call main # Execute main program
0x013: 00 | halt # Terminate program
|
| # Array of 4 elements
0x018: | .align 8
0x018: 0d000d000d000000 | array: .quad 0x000d000d000d
0x020: c000c000c0000000 | .quad 0x00c000c000c0
0x028: 000b000b000b0000 | .quad 0x0b000b000b00
0x030: 00a000a000a00000 | .quad 0xa000a000a000
|
0x038: 30f71800000000000000 | main: irmovq array,%rdi
0x042: 30f60400000000000000 | irmovq $4,%rsi
0x04c: 805600000000000000 | call sum # sum(array, 4)
0x055: 90 | ret
|
| /* $begin sumi-ys */
| # long sum(long *start, long count)
| # start in %rdi, count in %rsi
0x056: | sum:
0x056: 6300 | xorq %rax,%rax # sum = 0
0x058: 6266 | andq %rsi,%rsi # Set condition codes
0x05a: 708300000000000000 | jmp test
0x063: | loop:
0x063: 50a70000000000000000 | mrmovq (%rdi),%r10 # Get *start
0x06d: 60a0 | addq %r10,%rax # Add to sum
0x06f: c0f70800000000000000 | iaddq $8,%rdi # start++
0x079: c0f6ffffffffffffffff | iaddq $-1,%rsi # count--
0x083: | test:
0x083: 746300000000000000 | jne loop # Stop when 0
0x08c: 90 | ret
| /* $end sumi-ys */
|
| # The stack starts here and grows to lower addresses
0x100: | .pos 0x100
0x100: | stack:

View file

@ -0,0 +1,38 @@
# 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:

View file

@ -0,0 +1,42 @@
| # Execution begins at address 0
0x000: | .pos 0
0x000: 30f40002000000000000 | irmovq stack, %rsp # Set up stack pointer
0x00a: 803800000000000000 | call main # Execute main program
0x013: 00 | halt # Terminate program
|
| # Array of 4 elements
0x018: | .align 8
0x018: 0d000d000d000000 | array: .quad 0x000d000d000d
0x020: c000c000c0000000 | .quad 0x00c000c000c0
0x028: 000b000b000b0000 | .quad 0x0b000b000b00
0x030: 00a000a000a00000 | .quad 0xa000a000a000
|
0x038: 30f71800000000000000 | main: irmovq array,%rdi
0x042: 30f60400000000000000 | irmovq $4,%rsi
0x04c: 805600000000000000 | call rsum # rsum(array, 4)
0x055: 90 | ret
|
| /* $begin rsum-ys */
| # long rsum(long *start, long count)
| # start in %rdi, count in %rsi
0x056: | rsum:
0x056: 6300 | xorq %rax,%rax # Set return value to 0
0x058: 6266 | andq %rsi,%rsi # Set condition codes
0x05a: 739400000000000000 | je return # If count == 0, return 0
0x063: a03f | pushq %rbx # Save callee-saved register
0x065: 50370000000000000000 | mrmovq (%rdi),%rbx # Get *start
0x06f: 30faffffffffffffffff | irmovq $-1,%r10
0x079: 60a6 | addq %r10,%rsi # count--
0x07b: 30fa0800000000000000 | irmovq $8,%r10
0x085: 60a7 | addq %r10,%rdi # start++
0x087: 805600000000000000 | call rsum
0x090: 6030 | addq %rbx,%rax # Add *start to sum
0x092: b03f | popq %rbx # Restore callee-saved register
0x094: | return:
0x094: 90 | ret
| /* $end rsum-ys */
|
| # The stack starts here and grows to lower addresses
0x200: | .pos 0x200
0x200: | stack:
|

View file

@ -0,0 +1,42 @@
# 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
je 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:

View file

@ -0,0 +1,17 @@
| # /* $begin cjr-ys */
| # Code to generate a combination of not-taken branch and ret
0x000: 30f44000000000000000 | irmovq Stack, %rsp
0x00a: 30f03800000000000000 | irmovq rtnp,%rax
0x014: a00f | pushq %rax # Set up return pointer
0x016: 6300 | xorq %rax,%rax # Set Z condition code
0x018: 742c00000000000000 | jne target # Not taken (First part of combination)
0x021: 30f00100000000000000 | irmovq $1,%rax # Should execute this
0x02b: 00 | halt
0x02c: 90 | target: ret # Second part of combination
0x02d: 30f30200000000000000 | irmovq $2,%rbx # Should not execute this
0x037: 00 | halt
0x038: 30f20300000000000000 | rtnp: irmovq $3,%rdx # Should not execute this
0x042: 00 | halt
0x040: | .pos 0x40
0x040: | Stack:
| # /* $end cjr-ys */

View file

@ -0,0 +1,17 @@
# /* $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 */

View file

@ -0,0 +1,15 @@
0x000: 30f60100000000000000 | irmovq $1, %rsi
0x00a: 30f70200000000000000 | irmovq $2, %rdi
0x014: 30f50400000000000000 | irmovq $4, %rbp
0x01e: 30f0e0ffffffffffffff | irmovq $-32, %rax
0x028: 30f24000000000000000 | irmovq $64, %rdx
0x032: 6120 | subq %rdx,%rax
0x034: 733f00000000000000 | je target
0x03d: 10 | nop
0x03e: 00 | halt
0x03f: | target:
0x03f: 6062 | addq %rsi,%rdx
0x041: 10 | nop
0x042: 10 | nop
0x043: 10 | nop
0x044: 00 | halt

View file

@ -0,0 +1,15 @@
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

View file

@ -0,0 +1,6 @@
| # Test of Pop semantics for Y86-64
0x000: 30f40001000000000000 | irmovq $0x100,%rsp # Initialize stack pointer
0x00a: 30f0cdab000000000000 | irmovq $0xABCD,%rax
0x014: a00f | pushq %rax # Put known value on stack
0x016: b04f | popq %rsp # Either get 0xABCD, or 0xfc
0x018: 00 | halt

View file

@ -0,0 +1,6 @@
# 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

View file

@ -0,0 +1,8 @@
| # prog1: Pad with 3 nop's
0x000: 30f20a00000000000000 | irmovq $10,%rdx
0x00a: 30f00300000000000000 | irmovq $3,%rax
0x014: 10 | nop
0x015: 10 | nop
0x016: 10 | nop
0x017: 6020 | addq %rdx,%rax
0x019: 00 | halt

Some files were not shown because too many files have changed in this diff Show more