f
This commit is contained in:
commit
1fa36db752
238 changed files with 1790530 additions and 0 deletions
BIN
ArchLab/._archlab-handout
Executable file
BIN
ArchLab/._archlab-handout
Executable file
Binary file not shown.
BIN
ArchLab/archlab-handout.tar.gz
Normal file
BIN
ArchLab/archlab-handout.tar.gz
Normal file
Binary file not shown.
BIN
ArchLab/archlab-handout/.DS_Store
vendored
Normal file
BIN
ArchLab/archlab-handout/.DS_Store
vendored
Normal file
Binary file not shown.
36
ArchLab/archlab-handout/Makefile
Normal file
36
ArchLab/archlab-handout/Makefile
Normal 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
|
||||
|
||||
|
||||
|
22
ArchLab/archlab-handout/README
Normal file
22
ArchLab/archlab-handout/README
Normal 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
|
BIN
ArchLab/archlab-handout/archlab.pdf
Normal file
BIN
ArchLab/archlab-handout/archlab.pdf
Normal file
Binary file not shown.
BIN
ArchLab/archlab-handout/sim.tar
Normal file
BIN
ArchLab/archlab-handout/sim.tar
Normal file
Binary file not shown.
38
ArchLab/archlab-handout/sim/Makefile
Normal file
38
ArchLab/archlab-handout/sim/Makefile
Normal 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)
|
||||
|
97
ArchLab/archlab-handout/sim/README
Normal file
97
ArchLab/archlab-handout/sim/README
Normal 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
|
59
ArchLab/archlab-handout/sim/misc/Makefile
Normal file
59
ArchLab/archlab-handout/sim/misc/Makefile
Normal 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
|
||||
|
||||
|
71
ArchLab/archlab-handout/sim/misc/README
Normal file
71
ArchLab/archlab-handout/sim/misc/README
Normal 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}
|
||||
|
||||
|
45
ArchLab/archlab-handout/sim/misc/copy.ys
Normal file
45
ArchLab/archlab-handout/sim/misc/copy.ys
Normal 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:
|
50
ArchLab/archlab-handout/sim/misc/examples.c
Normal file
50
ArchLab/archlab-handout/sim/misc/examples.c
Normal 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 */
|
45
ArchLab/archlab-handout/sim/misc/hcl.lex
Normal file
45
ArchLab/archlab-handout/sim/misc/hcl.lex
Normal 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);
|
||||
%%
|
||||
|
1631
ArchLab/archlab-handout/sim/misc/hcl.tab.c
Normal file
1631
ArchLab/archlab-handout/sim/misc/hcl.tab.c
Normal file
File diff suppressed because it is too large
Load diff
86
ArchLab/archlab-handout/sim/misc/hcl.tab.h
Normal file
86
ArchLab/archlab-handout/sim/misc/hcl.tab.h
Normal 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 */
|
96
ArchLab/archlab-handout/sim/misc/hcl.y
Normal file
96
ArchLab/archlab-handout/sim/misc/hcl.y
Normal 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));}
|
||||
|
BIN
ArchLab/archlab-handout/sim/misc/hcl2c
Executable file
BIN
ArchLab/archlab-handout/sim/misc/hcl2c
Executable file
Binary file not shown.
943
ArchLab/archlab-handout/sim/misc/isa.c
Normal file
943
ArchLab/archlab-handout/sim/misc/isa.c
Normal 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;
|
||||
}
|
210
ArchLab/archlab-handout/sim/misc/isa.h
Normal file
210
ArchLab/archlab-handout/sim/misc/isa.h
Normal 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
|
BIN
ArchLab/archlab-handout/sim/misc/isa.o
Normal file
BIN
ArchLab/archlab-handout/sim/misc/isa.o
Normal file
Binary file not shown.
1968
ArchLab/archlab-handout/sim/misc/lex.yy.c
Normal file
1968
ArchLab/archlab-handout/sim/misc/lex.yy.c
Normal file
File diff suppressed because it is too large
Load diff
57
ArchLab/archlab-handout/sim/misc/mux4.hcl
Normal file
57
ArchLab/archlab-handout/sim/misc/mux4.hcl
Normal 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 */
|
703
ArchLab/archlab-handout/sim/misc/node.c
Normal file
703
ArchLab/archlab-handout/sim/misc/node.c
Normal 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 */
|
||||
}
|
35
ArchLab/archlab-handout/sim/misc/node.h
Normal file
35
ArchLab/archlab-handout/sim/misc/node.h
Normal 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
|
||||
|
71
ArchLab/archlab-handout/sim/misc/outgen.c
Normal file
71
ArchLab/archlab-handout/sim/misc/outgen.c
Normal 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;
|
||||
}
|
||||
|
||||
|
18
ArchLab/archlab-handout/sim/misc/outgen.h
Normal file
18
ArchLab/archlab-handout/sim/misc/outgen.h
Normal 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();
|
||||
|
||||
|
||||
|
40
ArchLab/archlab-handout/sim/misc/rsum.ys
Normal file
40
ArchLab/archlab-handout/sim/misc/rsum.ys
Normal 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:
|
40
ArchLab/archlab-handout/sim/misc/sum.ys
Normal file
40
ArchLab/archlab-handout/sim/misc/sum.ys
Normal 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:
|
BIN
ArchLab/archlab-handout/sim/misc/yas
Executable file
BIN
ArchLab/archlab-handout/sim/misc/yas
Executable file
Binary file not shown.
2120
ArchLab/archlab-handout/sim/misc/yas-grammar.c
Normal file
2120
ArchLab/archlab-handout/sim/misc/yas-grammar.c
Normal file
File diff suppressed because it is too large
Load diff
40
ArchLab/archlab-handout/sim/misc/yas-grammar.lex
Normal file
40
ArchLab/archlab-handout/sim/misc/yas-grammar.lex
Normal 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));
|
||||
}
|
BIN
ArchLab/archlab-handout/sim/misc/yas-grammar.o
Normal file
BIN
ArchLab/archlab-handout/sim/misc/yas-grammar.o
Normal file
Binary file not shown.
625
ArchLab/archlab-handout/sim/misc/yas.c
Normal file
625
ArchLab/archlab-handout/sim/misc/yas.c
Normal 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);
|
||||
}
|
13
ArchLab/archlab-handout/sim/misc/yas.h
Normal file
13
ArchLab/archlab-handout/sim/misc/yas.h
Normal 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;
|
BIN
ArchLab/archlab-handout/sim/misc/yas.o
Normal file
BIN
ArchLab/archlab-handout/sim/misc/yas.o
Normal file
Binary file not shown.
BIN
ArchLab/archlab-handout/sim/misc/yis
Executable file
BIN
ArchLab/archlab-handout/sim/misc/yis
Executable file
Binary file not shown.
64
ArchLab/archlab-handout/sim/misc/yis.c
Normal file
64
ArchLab/archlab-handout/sim/misc/yis.c
Normal 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;
|
||||
}
|
BIN
ArchLab/archlab-handout/sim/misc/yis.o
Normal file
BIN
ArchLab/archlab-handout/sim/misc/yis.o
Normal file
Binary file not shown.
63
ArchLab/archlab-handout/sim/pipe/Makefile
Normal file
63
ArchLab/archlab-handout/sim/pipe/Makefile
Normal 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 *~
|
||||
|
||||
|
150
ArchLab/archlab-handout/sim/pipe/README
Normal file
150
ArchLab/archlab-handout/sim/pipe/README
Normal 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
|
||||
|
||||
|
||||
|
110
ArchLab/archlab-handout/sim/pipe/benchmark.pl
Executable file
110
ArchLab/archlab-handout/sim/pipe/benchmark.pl
Executable 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;
|
||||
|
25
ArchLab/archlab-handout/sim/pipe/check-len.pl
Executable file
25
ArchLab/archlab-handout/sim/pipe/check-len.pl
Executable 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";
|
||||
}
|
139
ArchLab/archlab-handout/sim/pipe/correctness.pl
Executable file
139
ArchLab/archlab-handout/sim/pipe/correctness.pl
Executable 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";
|
||||
|
||||
|
||||
|
208
ArchLab/archlab-handout/sim/pipe/driver.yo
Normal file
208
ArchLab/archlab-handout/sim/pipe/driver.yo
Normal 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:
|
208
ArchLab/archlab-handout/sim/pipe/driver.ys
Normal file
208
ArchLab/archlab-handout/sim/pipe/driver.ys
Normal 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:
|
252
ArchLab/archlab-handout/sim/pipe/gen-driver.pl
Executable file
252
ArchLab/archlab-handout/sim/pipe/gen-driver.pl
Executable 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
|
||||
|
||||
|
292
ArchLab/archlab-handout/sim/pipe/ldriver.yo
Normal file
292
ArchLab/archlab-handout/sim/pipe/ldriver.yo
Normal 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:
|
292
ArchLab/archlab-handout/sim/pipe/ldriver.ys
Normal file
292
ArchLab/archlab-handout/sim/pipe/ldriver.ys
Normal 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:
|
44
ArchLab/archlab-handout/sim/pipe/ncopy.1.ys
Normal file
44
ArchLab/archlab-handout/sim/pipe/ncopy.1.ys
Normal 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 */
|
||||
|
71
ArchLab/archlab-handout/sim/pipe/ncopy.2.ys
Normal file
71
ArchLab/archlab-handout/sim/pipe/ncopy.2.ys
Normal 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 */
|
39
ArchLab/archlab-handout/sim/pipe/ncopy.c
Normal file
39
ArchLab/archlab-handout/sim/pipe/ncopy.c
Normal 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);
|
||||
}
|
||||
|
||||
|
117
ArchLab/archlab-handout/sim/pipe/ncopy.ys
Normal file
117
ArchLab/archlab-handout/sim/pipe/ncopy.ys
Normal 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 */
|
||||
|
293
ArchLab/archlab-handout/sim/pipe/pipe-full.c
Normal file
293
ArchLab/archlab-handout/sim/pipe/pipe-full.c
Normal 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;
|
||||
}
|
||||
|
390
ArchLab/archlab-handout/sim/pipe/pipe-full.hcl
Normal file
390
ArchLab/archlab-handout/sim/pipe/pipe-full.hcl
Normal 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 */
|
633
ArchLab/archlab-handout/sim/pipe/pipe.tcl
Executable file
633
ArchLab/archlab-handout/sim/pipe/pipe.tcl
Executable 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}
|
67
ArchLab/archlab-handout/sim/pipe/pipeline.h
Normal file
67
ArchLab/archlab-handout/sim/pipe/pipeline.h
Normal 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 */
|
||||
|
||||
|
||||
|
BIN
ArchLab/archlab-handout/sim/pipe/psim
Executable file
BIN
ArchLab/archlab-handout/sim/pipe/psim
Executable file
Binary file not shown.
1604
ArchLab/archlab-handout/sim/pipe/psim.c
Normal file
1604
ArchLab/archlab-handout/sim/pipe/psim.c
Normal file
File diff suppressed because it is too large
Load diff
174
ArchLab/archlab-handout/sim/pipe/sdriver.yo
Normal file
174
ArchLab/archlab-handout/sim/pipe/sdriver.yo
Normal 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:
|
174
ArchLab/archlab-handout/sim/pipe/sdriver.ys
Normal file
174
ArchLab/archlab-handout/sim/pipe/sdriver.ys
Normal 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:
|
153
ArchLab/archlab-handout/sim/pipe/sim.h
Normal file
153
ArchLab/archlab-handout/sim/pipe/sim.h
Normal 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
|
||||
|
90
ArchLab/archlab-handout/sim/pipe/stages.h
Normal file
90
ArchLab/archlab-handout/sim/pipe/stages.h
Normal 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();
|
||||
|
||||
|
20
ArchLab/archlab-handout/sim/ptest/Makefile
Normal file
20
ArchLab/archlab-handout/sim/ptest/Makefile
Normal 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
|
||||
|
36
ArchLab/archlab-handout/sim/ptest/README
Normal file
36
ArchLab/archlab-handout/sim/ptest/README
Normal 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.
|
113
ArchLab/archlab-handout/sim/ptest/ctest.pl
Executable file
113
ArchLab/archlab-handout/sim/ptest/ctest.pl
Executable 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();
|
||||
|
75
ArchLab/archlab-handout/sim/ptest/etest.pl
Executable file
75
ArchLab/archlab-handout/sim/ptest/etest.pl
Executable 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();
|
249
ArchLab/archlab-handout/sim/ptest/htest.pl
Executable file
249
ArchLab/archlab-handout/sim/ptest/htest.pl
Executable 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();
|
127
ArchLab/archlab-handout/sim/ptest/jtest.pl
Executable file
127
ArchLab/archlab-handout/sim/ptest/jtest.pl
Executable 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();
|
||||
|
||||
|
92
ArchLab/archlab-handout/sim/ptest/optest.pl
Executable file
92
ArchLab/archlab-handout/sim/ptest/optest.pl
Executable 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();
|
187
ArchLab/archlab-handout/sim/ptest/tester.pm
Normal file
187
ArchLab/archlab-handout/sim/ptest/tester.pm
Normal 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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
65
ArchLab/archlab-handout/sim/seq/Makefile
Normal file
65
ArchLab/archlab-handout/sim/seq/Makefile
Normal 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
|
||||
|
||||
|
||||
|
||||
|
91
ArchLab/archlab-handout/sim/seq/README
Normal file
91
ArchLab/archlab-handout/sim/seq/README
Normal 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)
|
||||
|
||||
|
226
ArchLab/archlab-handout/sim/seq/seq+-std.hcl
Normal file
226
ArchLab/archlab-handout/sim/seq/seq+-std.hcl
Normal 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 */
|
540
ArchLab/archlab-handout/sim/seq/seq+.tcl
Normal file
540
ArchLab/archlab-handout/sim/seq/seq+.tcl
Normal 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}
|
134
ArchLab/archlab-handout/sim/seq/seq-full.c
Normal file
134
ArchLab/archlab-handout/sim/seq/seq-full.c
Normal 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));
|
||||
}
|
||||
|
249
ArchLab/archlab-handout/sim/seq/seq-full.hcl
Normal file
249
ArchLab/archlab-handout/sim/seq/seq-full.hcl
Normal 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 */
|
540
ArchLab/archlab-handout/sim/seq/seq.tcl
Normal file
540
ArchLab/archlab-handout/sim/seq/seq.tcl
Normal 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}
|
108
ArchLab/archlab-handout/sim/seq/sim.h
Normal file
108
ArchLab/archlab-handout/sim/seq/sim.h
Normal 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
|
||||
|
BIN
ArchLab/archlab-handout/sim/seq/ssim
Executable file
BIN
ArchLab/archlab-handout/sim/seq/ssim
Executable file
Binary file not shown.
1169
ArchLab/archlab-handout/sim/seq/ssim.c
Normal file
1169
ArchLab/archlab-handout/sim/seq/ssim.c
Normal file
File diff suppressed because it is too large
Load diff
54
ArchLab/archlab-handout/sim/y86-code/Makefile
Normal file
54
ArchLab/archlab-handout/sim/y86-code/Makefile
Normal 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
|
20
ArchLab/archlab-handout/sim/y86-code/README
Normal file
20
ArchLab/archlab-handout/sim/y86-code/README
Normal 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.
|
||||
|
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-cmov.yo
Normal file
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-cmov.yo
Normal 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:
|
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-cmov.ys
Normal file
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-cmov.ys
Normal 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:
|
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-jmp.yo
Normal file
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-jmp.yo
Normal 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:
|
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-jmp.ys
Normal file
46
ArchLab/archlab-handout/sim/y86-code/abs-asum-jmp.ys
Normal 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:
|
35
ArchLab/archlab-handout/sim/y86-code/asum.yo
Normal file
35
ArchLab/archlab-handout/sim/y86-code/asum.yo
Normal 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:
|
35
ArchLab/archlab-handout/sim/y86-code/asum.ys
Normal file
35
ArchLab/archlab-handout/sim/y86-code/asum.ys
Normal 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:
|
38
ArchLab/archlab-handout/sim/y86-code/asumi.yo
Normal file
38
ArchLab/archlab-handout/sim/y86-code/asumi.yo
Normal 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:
|
38
ArchLab/archlab-handout/sim/y86-code/asumi.ys
Normal file
38
ArchLab/archlab-handout/sim/y86-code/asumi.ys
Normal 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:
|
42
ArchLab/archlab-handout/sim/y86-code/asumr.yo
Normal file
42
ArchLab/archlab-handout/sim/y86-code/asumr.yo
Normal 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:
|
||||
|
|
42
ArchLab/archlab-handout/sim/y86-code/asumr.ys
Normal file
42
ArchLab/archlab-handout/sim/y86-code/asumr.ys
Normal 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:
|
||||
|
17
ArchLab/archlab-handout/sim/y86-code/cjr.yo
Normal file
17
ArchLab/archlab-handout/sim/y86-code/cjr.yo
Normal 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 */
|
17
ArchLab/archlab-handout/sim/y86-code/cjr.ys
Normal file
17
ArchLab/archlab-handout/sim/y86-code/cjr.ys
Normal 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 */
|
15
ArchLab/archlab-handout/sim/y86-code/j-cc.yo
Normal file
15
ArchLab/archlab-handout/sim/y86-code/j-cc.yo
Normal 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
|
15
ArchLab/archlab-handout/sim/y86-code/j-cc.ys
Normal file
15
ArchLab/archlab-handout/sim/y86-code/j-cc.ys
Normal 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
|
6
ArchLab/archlab-handout/sim/y86-code/poptest.yo
Normal file
6
ArchLab/archlab-handout/sim/y86-code/poptest.yo
Normal 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
|
6
ArchLab/archlab-handout/sim/y86-code/poptest.ys
Normal file
6
ArchLab/archlab-handout/sim/y86-code/poptest.ys
Normal 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
|
8
ArchLab/archlab-handout/sim/y86-code/prog1.yo
Normal file
8
ArchLab/archlab-handout/sim/y86-code/prog1.yo
Normal 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
Loading…
Reference in a new issue