diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/compose.yaml b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/compose.yaml new file mode 100644 index 00000000..cc530820 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/compose.yaml @@ -0,0 +1,9 @@ +services: + default: + image: ubuntu:22.04 + init: true + command: sleep infinity + working_dir: /workspace + network_mode: bridge + cpus: '2' + mem_limit: 2048mb diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/config.json b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/config.json new file mode 100644 index 00000000..8bc19170 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/config.json @@ -0,0 +1,20 @@ +{ + "instance_id": "cmu_15-213__architecture_lab", + "course_id": "cmu_15-213", + "timeout_minutes": 90, + "tags": [ + "computer-architecture", + "pipeline", + "assembly", + "performance", + "y86-64" + ], + "artifacts": [ + "sim/pipe/ncopy.ys", + "sim/pipe/pipe-std.hcl", + "sim/pipe/pipe-full.hcl", + "sim/pipe/pipe-lf.hcl", + "sim/pipe/pipe-nt.hcl", + "sim/pipe/pipe-btfnt.hcl" + ] +} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/evaluate.sh b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/evaluate.sh new file mode 100755 index 00000000..16c60d9e --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/evaluate.sh @@ -0,0 +1,143 @@ +# !/bin/bash +# Redirect stderr to stdout so Inspect AI doesn't treat warnings as failures +exec 2>&1 +set -euo pipefail + +echo "=== Evaluating Architecture Lab ===" +cd /workspace + +SIM_DIR="/workspace/sim" +CPE_THRESHOLD=10.5 + +# Ensure required source files exist +for f in "pipe/ncopy.ys" "pipe/benchmark.pl" "pipe/correctness.pl"; do + if [ ! -e "$SIM_DIR/$f" ]; then + echo "FAIL: Missing $f" + exit 1 + fi +done + +cd /workspace + +HCL="sim/pipe/pipe-full.hcl" +NCOPY="sim/pipe/ncopy.ys" + +######################################################################## +# Part 1: Patch pipe-full.hcl to add iaddq (IIADDQ) support +######################################################################## + +# 1a. instr_valid – add IIADDQ as a valid instruction +sed -i 's/IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }/IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ, IIADDQ }/' "$HCL" + +# 1b. need_regids – iaddq has a register specifier byte +sed -i 's/IIRMOVQ, IRMMOVQ, IMRMOVQ }/IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ }/' "$HCL" + +# 1c. need_valC – iaddq has a constant word +sed -i 's/IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }/IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL, IIADDQ }/' "$HCL" + +# 1d. d_srcB – iaddq reads rB +sed -i 's/D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB/D_icode in { IOPQ, IRMMOVQ, IMRMOVQ, IIADDQ } : D_rB/' "$HCL" + +# 1e. d_dstE – iaddq writes result to rB +sed -i 's/D_icode in { IRRMOVQ, IIRMOVQ, IOPQ}/D_icode in { IRRMOVQ, IIRMOVQ, IOPQ, IIADDQ}/' "$HCL" + +# 1f. aluA – iaddq feeds valC to ALU input A +sed -i 's/E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC/E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ } : E_valC/' "$HCL" + +# 1g. aluB – iaddq feeds valB to ALU input B +sed -i 's/E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL,/E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IIADDQ,/' "$HCL" + +# 1h. set_cc – iaddq updates condition codes (like OPQ) +sed -i 's/bool set_cc = E_icode == IOPQ/bool set_cc = E_icode in { IOPQ, IIADDQ }/' "$HCL" + +######################################################################## +# Part 2: Rewrite ncopy.ys using iaddq for fewer instructions per iter +######################################################################## + +cat > "$NCOPY" << 'NCOPY_EOF' +#/* $begin ncopy-ys */ +################################################################## +# ncopy.ys - Copy a src block of len words to dst. +# Return the number of positive words (>0) contained in src. +# +# Solution: use iaddq to replace irmovq+addq pairs. +# This reduces instructions per loop iteration from 12 to 8, +# yielding CPE ≈ 9.0 (well below the 10.5 threshold). +################################################################## +# Do not modify this portion +# Function prologue. +# %rdi = src, %rsi = dst, %rdx = len +ncopy: + +################################################################## +# You can modify this portion + 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 */ +NCOPY_EOF + +cd "$SIM_DIR" + +echo "Rebuilding tools (TTY mode)" +make clean > /dev/null 2>&1 || true +if ! make all GUIMODE= TKLIBS= TKINC=; then + echo "FAIL: Build failed" + exit 1 +fi + +echo "Rebuilding psim from pipe-full.hcl" +cd pipe +if ! make psim VERSION=full GUIMODE= TKLIBS= TKINC=; then + echo "FAIL: psim build from pipe-full.hcl failed" + exit 1 +fi + +echo "Generating drivers" +if ! make drivers; then + echo "FAIL: make drivers failed" + exit 1 +fi + +echo "Running correctness (pipeline)" +if ! ./correctness.pl -q -p -f ncopy.ys; then + echo "FAIL: correctness check failed" + exit 1 +fi + +echo "Running benchmark" +BENCH_OUTPUT=$(./benchmark.pl -q -f ncopy.ys) +echo "$BENCH_OUTPUT" + +acpe=$(echo "$BENCH_OUTPUT" | awk '/Average CPE/{print $3}' | tail -n1) +echo "Average CPE: ${acpe}" +if [ -z "$acpe" ]; then + echo "FAIL: Could not parse CPE" + exit 1 +fi +if awk "BEGIN { if ($acpe > $CPE_THRESHOLD) exit 1; }"; then + echo "PASS: Architecture lab correctness + performance goal met (CPE=$acpe <= $CPE_THRESHOLD)" + exit 0 +else + echo "FAIL: CPE $acpe exceeds threshold $CPE_THRESHOLD" + exit 1 +fi \ No newline at end of file diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/preprocess.sh b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/preprocess.sh new file mode 100755 index 00000000..727a19c0 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/preprocess.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# Preprocess: install dependencies and build Y86-64 toolchain +# NOTE: All stderr is redirected to stdout to prevent Inspect AI from +# treating harmless warnings (e.g. debconf) as fatal errors. +exec 2>&1 +set -euo pipefail + +export DEBIAN_FRONTEND=noninteractive + +echo "=== Setting up CMU 15-213 Architecture Lab ===" +cd /workspace + +# if [ -f /etc/apt/sources.list.d/debian.sources ]; then +# sed -i 's@deb.debian.org@mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list.d/debian.sources +# fi +sed -i 's|http://archive.ubuntu.com|http://mirrors.aliyun.com|g; s|http://security.ubuntu.com|http://mirrors.aliyun.com|g' /etc/apt/sources.list + +# 1. Install core dependencies +apt-get update -y -qq +apt-get install -y -qq --no-install-recommends \ + build-essential gcc-multilib gdb binutils make \ + python3 perl bison flex libfl-dev ca-certificates + +SIM_DIR="/workspace/sim" +if [ ! -d "$SIM_DIR" ]; then + echo "ERROR: sim directory not found"; exit 1 +fi + +# 2. Patch Makefiles (Architecture Lab specific fixes) +echo "Patching Makefiles..." +# -fcommon: fix duplicate global variable definitions (GCC 10+) +# -lfl: replace old -ll to work with modern flex library +find "$SIM_DIR" -name "Makefile" -exec sed -i 's/^CFLAGS=.*/CFLAGS=-Wall -O1 -g -fcommon -Wno-error/g' {} + +find "$SIM_DIR" -name "Makefile" -exec sed -i 's/^LCFLAGS=.*/LCFLAGS=-O1 -fcommon/g' {} + +find "$SIM_DIR" -name "Makefile" -exec sed -i 's/-ll/-lfl/g' {} + + +# Force-disable GUI options in all subdirectory Makefiles +for m in "$SIM_DIR/Makefile" "$SIM_DIR/pipe/Makefile" "$SIM_DIR/seq/Makefile" "$SIM_DIR/misc/Makefile"; do + if [ -f "$m" ]; then + sed -i 's/^GUIMODE=.*/GUIMODE=/' "$m" + sed -i 's/^TKLIBS=.*/TKLIBS=/' "$m" + sed -i 's/^TKINC=.*/TKINC=/' "$m" + fi +done + +# 3. Fix permissions on Perl scripts +find "$SIM_DIR" -name "*.pl" -exec chmod +x {} + + +# 4. Clean any stale object files, then build Y86-64 tools +cd "$SIM_DIR" +make clean > /dev/null 2>&1 || true + +if ! make all GUIMODE=; then + echo "========= !! BUILD FAILED !! =========" + exit 1 +fi + +# 4. Verify that critical tools were built +for f in misc/yas misc/yis pipe/psim; do + if [ ! -f "$SIM_DIR/$f" ]; then + echo "ERROR: $f not found after build" + exit 1 + fi +done + +echo "Setup complete" +exit 0 \ No newline at end of file diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/sol.sh b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/sol.sh new file mode 100755 index 00000000..d47729c9 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/sol.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# Reference solution for CMU 15-213 Architecture Lab (Part C) +# +# Strategy: +# 1. Patch pipe-full.hcl to implement the iaddq instruction in the PIPE processor +# 2. Rewrite ncopy.ys using iaddq to eliminate irmovq/addq pairs, lowering CPE +# +# Expected result: correctness passes, Average CPE ≈ 9.0–9.5 (well under 10.5 threshold) +set -euo pipefail + +cd /workspace + +HCL="sim/pipe/pipe-full.hcl" +NCOPY="sim/pipe/ncopy.ys" + +######################################################################## +# Part 1: Patch pipe-full.hcl to add iaddq (IIADDQ) support +######################################################################## + +# 1a. instr_valid – add IIADDQ as a valid instruction +sed -i 's/IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }/IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ, IIADDQ }/' "$HCL" + +# 1b. need_regids – iaddq has a register specifier byte +sed -i 's/IIRMOVQ, IRMMOVQ, IMRMOVQ }/IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ }/' "$HCL" + +# 1c. need_valC – iaddq has a constant word +sed -i 's/IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }/IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL, IIADDQ }/' "$HCL" + +# 1d. d_srcB – iaddq reads rB +sed -i 's/D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB/D_icode in { IOPQ, IRMMOVQ, IMRMOVQ, IIADDQ } : D_rB/' "$HCL" + +# 1e. d_dstE – iaddq writes result to rB +sed -i 's/D_icode in { IRRMOVQ, IIRMOVQ, IOPQ}/D_icode in { IRRMOVQ, IIRMOVQ, IOPQ, IIADDQ}/' "$HCL" + +# 1f. aluA – iaddq feeds valC to ALU input A +sed -i 's/E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC/E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ } : E_valC/' "$HCL" + +# 1g. aluB – iaddq feeds valB to ALU input B +sed -i 's/E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL,/E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IIADDQ,/' "$HCL" + +# 1h. set_cc – iaddq updates condition codes (like OPQ) +sed -i 's/bool set_cc = E_icode == IOPQ/bool set_cc = E_icode in { IOPQ, IIADDQ }/' "$HCL" + +######################################################################## +# Part 2: Rewrite ncopy.ys using iaddq for fewer instructions per iter +######################################################################## + +cat > "$NCOPY" << 'NCOPY_EOF' +#/* $begin ncopy-ys */ +################################################################## +# ncopy.ys - Copy a src block of len words to dst. +# Return the number of positive words (>0) contained in src. +# +# Solution: use iaddq to replace irmovq+addq pairs. +# This reduces instructions per loop iteration from 12 to 8, +# yielding CPE ≈ 9.0 (well below the 10.5 threshold). +################################################################## +# Do not modify this portion +# Function prologue. +# %rdi = src, %rsi = dst, %rdx = len +ncopy: + +################################################################## +# You can modify this portion + 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 */ +NCOPY_EOF + +echo "Solution applied: pipe-full.hcl patched with iaddq + ncopy.ys optimized" diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/Makefile b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/Makefile new file mode 100644 index 00000000..e673e347 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/Makefile @@ -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= + +# 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= + +################################################## +# 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) + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/README b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/README new file mode 100644 index 00000000..95f15611 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/README @@ -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 diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/Makefile b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/Makefile new file mode 100644 index 00000000..673bd252 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/Makefile @@ -0,0 +1,59 @@ +CC=gcc +CFLAGS=-Wall -O1 -g -fcommon -Wno-error +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 + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/README b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/README new file mode 100644 index 00000000..e1cbdd5a --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/README @@ -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} + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/examples.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/examples.c new file mode 100644 index 00000000..6f09d43c --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/examples.c @@ -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 */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/hcl.lex b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/hcl.lex new file mode 100644 index 00000000..f2ca313d --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/hcl.lex @@ -0,0 +1,45 @@ +%{ +#include +#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); +%% + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/hcl.y b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/hcl.y new file mode 100644 index 00000000..269a2f62 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/hcl.y @@ -0,0 +1,96 @@ +%{ +#include +#include +#include +#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));} + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.c new file mode 100644 index 00000000..484e4222 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.c @@ -0,0 +1,943 @@ +#include +#include +#include +#include +#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 ""; +} + + +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; +} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.h new file mode 100644 index 00000000..227cbffe --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.h @@ -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 diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.o b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.o new file mode 100644 index 00000000..1a7fbf69 Binary files /dev/null and b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/isa.o differ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/mux4.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/mux4.hcl new file mode 100644 index 00000000..6e144669 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/mux4.hcl @@ -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 ' +quote '#include ' +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 */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/node.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/node.c new file mode 100644 index 00000000..1f359388 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/node.c @@ -0,0 +1,703 @@ +/* Functions to generate C or Verilog code from HCL */ +/* This file maintains a parse tree representation of expressions */ + +#include +#include +#include +#include +#include + +#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 */ +} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/node.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/node.h new file mode 100644 index 00000000..b3625923 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/node.h @@ -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 + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/outgen.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/outgen.c new file mode 100644 index 00000000..e51c65f5 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/outgen.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#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; +} + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/outgen.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/outgen.h new file mode 100644 index 00000000..1a487021 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/outgen.h @@ -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(); + + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.c new file mode 100644 index 00000000..a1dded88 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.c @@ -0,0 +1,2100 @@ + +#line 3 "lex.yy.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +#define YY_NUM_RULES 16 +#define YY_END_OF_BUFFER 17 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_acclist[291] = + { 0, + 17, 14, 16, 6, 14, 16, 5, 16, 5, 16, + 14, 16, 7, 14, 16, 14, 16, 12, 14, 16, + 14, 16, 14, 16, 14, 16, 10, 14, 16, 10, + 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, + 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, + 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, + 14, 16, 13, 14, 16, 13, 14, 16, 14, 16, + 6, 14, 16, 1, 5, 16, 1, 5, 16, 14, + 16, 7, 14, 16, 14, 16, 12, 14, 16, 14, + 16, 14, 16, 14, 16, 10, 14, 16, 10, 14, + + 16, 13, 14, 16, 13, 14, 16, 13, 14, 16, + 13, 14, 16, 13, 14, 16, 13, 14, 16, 13, + 14, 16, 13, 14, 16, 13, 14, 16, 13, 14, + 16, 13, 14, 16, 13, 14, 16, 16, 15, 16, + 16, 6, 5, 5, 2, 2, 7, 10, 13, 13, + 13, 13, 13, 13, 13, 13, 8, 13, 8, 13, + 8, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 1, 1, 6, 1, 5, 1, 5, + 1, 2, 1, 2, 7, 10, 13, 13, 13, 13, + 13, 13, 13, 13, 8, 13, 8, 13, 8, 13, + + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 15, 9, 4, 4, 3, 3, 11, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 9, 1, 4, 1, 4, 1, 3, 1, + 3, 11, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 8, 13, 13, 13, + 13, 13, 13, 13, 8, 13, 13, 13, 13, 13, + 13, 13, 8, 13, 8, 13, 13, 13, 13, 13, + 13, 8, 13, 8, 13, 13, 13, 13, 13, 13 + } ; + +static const flex_int16_t yy_accept[258] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 2, 4, 7, + 9, 11, 13, 16, 18, 21, 23, 25, 27, 30, + 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, + 63, 66, 69, 71, 74, 77, 80, 82, 85, 87, + 90, 92, 94, 96, 99, 102, 105, 108, 111, 114, + 117, 120, 123, 126, 129, 132, 135, 138, 139, 141, + 142, 143, 144, 145, 145, 146, 147, 148, 148, 149, + 149, 149, 149, 149, 149, 149, 149, 149, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 159, 161, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, + + 174, 174, 175, 176, 177, 179, 181, 181, 183, 185, + 186, 186, 187, 187, 187, 187, 187, 187, 187, 187, + 187, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 197, 199, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 212, 213, 213, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 215, 216, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 234, 234, 236, 238, 238, 240, 242, 243, + + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 257, 257, 257, 258, 258, 258, + 259, 260, 261, 262, 263, 264, 265, 265, 265, 265, + 266, 266, 266, 267, 268, 269, 270, 271, 272, 273, + 273, 275, 277, 278, 279, 280, 281, 282, 282, 284, + 286, 287, 288, 289, 290, 291, 291 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 5, 6, 7, 1, 1, 8, + 8, 9, 1, 8, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 18, 18, 19, 20, 8, 1, 1, + 1, 1, 1, 1, 21, 21, 21, 21, 21, 21, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 23, 22, 22, + 1, 1, 1, 1, 24, 1, 25, 26, 27, 28, + + 29, 21, 30, 31, 32, 33, 22, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 22, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[48] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 4, 4, 4, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4 + } ; + +static const flex_int16_t yy_base[271] = + { 0, + 0, 47, 92, 94, 0, 0, 691, 692, 97, 692, + 99, 101, 684, 649, 692, 0, 81, 99, 86, 0, + 0, 82, 87, 663, 88, 95, 647, 649, 80, 98, + 642, 647, 131, 137, 692, 133, 139, 141, 145, 147, + 183, 201, 149, 123, 0, 246, 258, 129, 131, 135, + 144, 148, 153, 178, 182, 134, 155, 190, 692, 692, + 205, 692, 209, 216, 692, 220, 677, 281, 0, 648, + 634, 643, 642, 635, 640, 225, 227, 0, 0, 648, + 647, 640, 636, 638, 643, 635, 0, 640, 639, 629, + 637, 630, 626, 625, 621, 619, 625, 574, 582, 567, + + 229, 692, 233, 239, 692, 241, 268, 692, 270, 272, + 320, 0, 276, 278, 280, 284, 286, 289, 293, 295, + 349, 249, 275, 276, 299, 277, 302, 292, 314, 315, + 324, 343, 345, 356, 352, 358, 361, 354, 365, 370, + 374, 385, 372, 312, 692, 341, 692, 560, 376, 559, + 136, 299, 572, 560, 561, 554, 548, 531, 315, 692, + 400, 412, 692, 414, 0, 518, 512, 515, 503, 490, + 502, 487, 484, 478, 480, 459, 455, 451, 427, 416, + 420, 422, 424, 431, 433, 435, 437, 439, 442, 444, + 446, 448, 450, 692, 452, 454, 692, 456, 0, 436, + + 448, 446, 455, 458, 461, 465, 467, 470, 477, 479, + 482, 484, 486, 433, 432, 414, 692, 363, 331, 497, + 305, 297, 288, 263, 247, 194, 525, 531, 533, 535, + 537, 539, 516, 520, 525, 526, 536, 530, 540, 198, + 196, 187, 166, 127, 116, 82, 77, 574, 551, 553, + 557, 555, 560, 562, 564, 692, 610, 614, 618, 112, + 621, 625, 629, 633, 637, 641, 645, 648, 651, 655 + } ; + +static const flex_int16_t yy_def[271] = + { 0, + 256, 256, 257, 257, 258, 258, 256, 256, 256, 256, + 256, 259, 256, 256, 256, 260, 256, 256, 260, 260, + 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, + 261, 261, 262, 262, 256, 256, 263, 262, 262, 262, + 262, 262, 262, 41, 41, 264, 264, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 265, 256, 256, + 256, 256, 256, 259, 256, 256, 256, 256, 260, 256, + 256, 256, 256, 256, 256, 266, 267, 268, 261, 261, + 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, + 261, 261, 261, 261, 261, 261, 261, 261, 261, 261, + + 262, 256, 256, 262, 256, 256, 263, 256, 256, 262, + 262, 41, 262, 262, 262, 262, 262, 262, 269, 270, + 41, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 265, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 266, 256, + 256, 267, 256, 256, 268, 261, 261, 261, 261, 261, + 261, 261, 261, 261, 261, 261, 261, 261, 261, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 269, 256, 256, 270, 256, 256, 121, 47, + + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 256, 256, 256, 256, 256, 256, 261, + 261, 261, 261, 261, 261, 261, 262, 262, 262, 262, + 262, 262, 47, 47, 47, 47, 47, 47, 47, 256, + 261, 261, 261, 261, 261, 261, 261, 262, 47, 47, + 47, 47, 47, 47, 47, 0, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256 + } ; + +static const flex_int16_t yy_nxt[740] = + { 0, + 8, 9, 10, 11, 12, 13, 14, 15, 8, 16, + 17, 18, 19, 20, 20, 20, 20, 20, 20, 20, + 21, 21, 21, 8, 22, 21, 23, 21, 21, 21, + 24, 25, 26, 21, 27, 28, 21, 29, 21, 30, + 31, 21, 21, 21, 21, 32, 21, 33, 34, 35, + 36, 37, 38, 39, 40, 33, 41, 42, 43, 44, + 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, + 33, 47, 46, 48, 46, 46, 46, 49, 50, 51, + 46, 52, 53, 46, 54, 46, 55, 56, 46, 46, + 46, 46, 57, 46, 59, 59, 59, 59, 61, 62, + + 63, 62, 63, 65, 66, 70, 71, 76, 78, 80, + 77, 82, 85, 69, 72, 87, 94, 81, 73, 74, + 87, 83, 95, 87, 88, 75, 96, 86, 89, 90, + 91, 78, 97, 102, 103, 105, 106, 98, 104, 105, + 106, 108, 109, 102, 103, 121, 110, 102, 103, 102, + 103, 102, 103, 125, 87, 127, 122, 119, 122, 128, + 120, 122, 122, 126, 122, 87, 122, 147, 121, 122, + 122, 122, 130, 131, 129, 122, 142, 132, 133, 134, + 122, 147, 122, 122, 111, 102, 103, 135, 122, 136, + 122, 143, 145, 145, 87, 112, 112, 112, 112, 112, + + 112, 112, 112, 102, 103, 122, 61, 62, 63, 122, + 139, 62, 63, 122, 137, 87, 140, 122, 65, 66, + 138, 141, 65, 66, 87, 113, 114, 160, 161, 163, + 164, 102, 103, 217, 115, 102, 103, 247, 116, 117, + 104, 105, 106, 105, 106, 118, 101, 101, 102, 103, + 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, + 102, 103, 101, 101, 101, 101, 101, 101, 101, 101, + 108, 109, 108, 109, 102, 103, 122, 110, 102, 103, + 102, 103, 102, 103, 122, 123, 102, 103, 102, 103, + 246, 102, 103, 124, 146, 194, 195, 197, 198, 147, + + 147, 87, 200, 201, 122, 148, 149, 150, 151, 187, + 122, 122, 122, 203, 145, 145, 189, 160, 161, 205, + 190, 152, 102, 103, 188, 192, 122, 122, 191, 122, + 147, 245, 202, 180, 122, 204, 147, 122, 181, 181, + 244, 122, 122, 87, 182, 183, 184, 185, 206, 122, + 122, 122, 130, 147, 147, 147, 147, 147, 217, 122, + 186, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 122, 130, 122, 199, 199, 199, 199, 199, 122, 122, + 122, 122, 130, 122, 130, 122, 207, 122, 122, 122, + 217, 122, 122, 122, 209, 130, 122, 122, 208, 122, + + 122, 122, 160, 161, 210, 122, 130, 122, 211, 122, + 212, 213, 122, 147, 163, 164, 163, 164, 102, 103, + 122, 147, 102, 103, 102, 103, 102, 103, 181, 181, + 181, 181, 181, 102, 103, 102, 103, 102, 103, 102, + 103, 102, 103, 217, 102, 103, 102, 103, 102, 103, + 102, 103, 194, 195, 194, 195, 197, 198, 197, 198, + 217, 181, 240, 122, 181, 87, 181, 181, 227, 181, + 231, 122, 181, 122, 130, 122, 181, 229, 181, 130, + 228, 122, 122, 122, 230, 122, 130, 232, 234, 87, + 122, 226, 122, 122, 122, 225, 122, 122, 233, 130, + + 122, 235, 122, 236, 122, 122, 122, 237, 130, 122, + 224, 122, 122, 122, 122, 238, 87, 122, 239, 122, + 223, 122, 130, 222, 130, 87, 241, 102, 103, 221, + 242, 87, 243, 102, 103, 102, 103, 102, 103, 102, + 103, 102, 103, 122, 130, 249, 220, 122, 87, 250, + 87, 251, 122, 122, 248, 122, 87, 122, 130, 230, + 122, 122, 230, 122, 230, 122, 230, 122, 252, 253, + 219, 122, 218, 254, 130, 122, 102, 103, 122, 130, + 122, 130, 122, 255, 122, 130, 122, 122, 122, 122, + 122, 122, 122, 130, 217, 122, 216, 122, 130, 122, + + 130, 215, 130, 214, 147, 147, 179, 178, 177, 230, + 58, 58, 58, 58, 60, 60, 60, 60, 64, 64, + 64, 64, 79, 79, 79, 101, 101, 101, 101, 107, + 107, 107, 107, 122, 122, 122, 122, 144, 144, 144, + 144, 159, 159, 159, 159, 162, 162, 162, 162, 165, + 165, 193, 193, 193, 193, 196, 196, 196, 196, 176, + 87, 175, 174, 87, 173, 87, 87, 87, 87, 172, + 171, 170, 169, 168, 167, 166, 158, 157, 156, 155, + 154, 153, 67, 100, 99, 93, 92, 84, 68, 67, + 256, 7, 256, 256, 256, 256, 256, 256, 256, 256, + + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256 + } ; + +static const flex_int16_t yy_chk[740] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 4, 4, 9, 9, + + 9, 11, 11, 12, 12, 17, 17, 18, 19, 22, + 18, 23, 25, 260, 17, 247, 29, 22, 17, 17, + 246, 23, 29, 26, 26, 17, 30, 25, 26, 26, + 26, 19, 30, 33, 33, 36, 36, 30, 34, 34, + 34, 37, 37, 38, 38, 44, 38, 39, 39, 40, + 40, 43, 43, 48, 245, 49, 48, 43, 49, 50, + 43, 56, 50, 48, 48, 244, 49, 151, 44, 56, + 50, 51, 51, 51, 50, 52, 56, 51, 51, 51, + 53, 151, 57, 52, 39, 41, 41, 52, 53, 53, + 57, 57, 58, 58, 243, 41, 41, 41, 41, 41, + + 41, 41, 41, 42, 42, 54, 61, 61, 61, 55, + 55, 63, 63, 54, 54, 242, 55, 55, 64, 64, + 54, 55, 66, 66, 241, 42, 42, 76, 76, 77, + 77, 101, 101, 240, 42, 103, 103, 226, 42, 42, + 104, 104, 104, 106, 106, 42, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 107, 107, 109, 109, 110, 110, 122, 110, 113, 113, + 114, 114, 115, 115, 122, 47, 116, 116, 117, 117, + 225, 118, 118, 47, 68, 119, 119, 120, 120, 68, + + 68, 224, 123, 124, 126, 68, 68, 68, 68, 113, + 123, 124, 126, 126, 144, 144, 115, 159, 159, 128, + 116, 68, 111, 111, 114, 118, 125, 128, 117, 127, + 152, 223, 125, 111, 125, 127, 152, 127, 111, 111, + 222, 129, 130, 221, 111, 111, 111, 111, 129, 129, + 130, 131, 131, 146, 146, 146, 146, 146, 219, 131, + 111, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 132, 132, 133, 121, 121, 121, 121, 121, 132, 135, + 133, 138, 133, 134, 134, 136, 135, 135, 137, 138, + 218, 134, 139, 136, 138, 136, 137, 140, 137, 143, + + 139, 141, 161, 161, 140, 140, 139, 143, 141, 141, + 142, 143, 142, 149, 162, 162, 164, 164, 180, 180, + 142, 149, 181, 181, 182, 182, 183, 183, 180, 180, + 180, 180, 180, 184, 184, 185, 185, 186, 186, 187, + 187, 188, 188, 216, 189, 189, 190, 190, 191, 191, + 192, 192, 193, 193, 195, 195, 196, 196, 198, 198, + 215, 183, 214, 200, 185, 179, 186, 182, 187, 183, + 191, 200, 186, 202, 200, 201, 184, 189, 185, 202, + 188, 202, 203, 201, 190, 204, 201, 192, 205, 178, + 203, 177, 206, 204, 207, 176, 205, 208, 203, 204, + + 206, 206, 207, 207, 209, 208, 210, 209, 208, 211, + 175, 212, 209, 213, 210, 210, 174, 211, 211, 212, + 173, 213, 212, 172, 213, 220, 220, 227, 227, 171, + 220, 170, 220, 228, 228, 229, 229, 230, 230, 231, + 231, 232, 232, 233, 233, 233, 169, 234, 168, 233, + 167, 233, 235, 236, 227, 234, 166, 238, 234, 228, + 235, 236, 229, 237, 231, 238, 232, 239, 235, 236, + 158, 237, 157, 238, 237, 239, 248, 248, 249, 249, + 250, 250, 252, 239, 251, 251, 249, 253, 250, 254, + 252, 255, 251, 252, 156, 253, 155, 254, 253, 255, + + 254, 154, 255, 153, 150, 148, 100, 99, 98, 248, + 257, 257, 257, 257, 258, 258, 258, 258, 259, 259, + 259, 259, 261, 261, 261, 262, 262, 262, 262, 263, + 263, 263, 263, 264, 264, 264, 264, 265, 265, 265, + 265, 266, 266, 266, 266, 267, 267, 267, 267, 268, + 268, 269, 269, 269, 269, 270, 270, 270, 270, 97, + 96, 95, 94, 93, 92, 91, 90, 89, 88, 86, + 85, 84, 83, 82, 81, 80, 75, 74, 73, 72, + 71, 70, 67, 32, 31, 28, 27, 24, 14, 13, + 7, 256, 256, 256, 256, 256, 256, 256, 256, 256, + + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256 + } ; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +static yy_state_type *yy_state_buf=0, *yy_state_ptr=0; +static char *yy_full_match; +static int yy_lp; +#define REJECT \ +{ \ +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \ +yy_cp = (yy_full_match); /* restore poss. backed-over text */ \ +++(yy_lp); \ +goto find_rule; \ +} + +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "yas-grammar.lex" +/* Grammar for Y86-64 Assembler */ +#line 3 "yas-grammar.lex" + #include "yas.h" + +#line 731 "lex.yy.c" + +#define INITIAL 0 +#define ERR 1 +#define COM 2 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals ( void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr ); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + /* Create the reject buffer large enough to save one state per allowed character. */ + if ( ! (yy_state_buf) ) + (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE ); + if ( ! (yy_state_buf) ) + YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 17 "yas-grammar.lex" + + +#line 962 "lex.yy.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); + + (yy_state_ptr) = (yy_state_buf); + *(yy_state_ptr)++ = yy_current_state; + +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 257 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + *(yy_state_ptr)++ = yy_current_state; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 692 ); + +yy_find_action: + yy_current_state = *--(yy_state_ptr); + (yy_lp) = yy_accept[yy_current_state]; + +find_rule: /* we branch to this label when backing up */ + + for ( ; ; ) /* until we find what rule we matched */ + { + if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] ) + { + yy_act = yy_acclist[(yy_lp)]; + { + (yy_full_match) = yy_cp; + break; + } + } + --yy_cp; + yy_current_state = *--(yy_state_ptr); + (yy_lp) = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 19 "yas-grammar.lex" +{ save_line(yytext); REJECT;} /* Snarf input line */ + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 20 "yas-grammar.lex" +{finish_line(); lineno++;} + YY_BREAK +case 3: +/* rule 3 can match eol */ +YY_RULE_SETUP +#line 21 "yas-grammar.lex" +{finish_line(); lineno++;} + YY_BREAK +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +#line 22 "yas-grammar.lex" +{finish_line(); lineno++;} + YY_BREAK +case 5: +/* rule 5 can match eol */ +YY_RULE_SETUP +#line 23 "yas-grammar.lex" +{finish_line(); lineno++;} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 25 "yas-grammar.lex" +; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 26 "yas-grammar.lex" +; + YY_BREAK +case 8: +YY_RULE_SETUP +#line 27 "yas-grammar.lex" +add_instr(yytext); + YY_BREAK +case 9: +YY_RULE_SETUP +#line 28 "yas-grammar.lex" +add_reg(yytext); + YY_BREAK +case 10: +YY_RULE_SETUP +#line 29 "yas-grammar.lex" +add_num(atoll(yytext)); + YY_BREAK +case 11: +YY_RULE_SETUP +#line 30 "yas-grammar.lex" +add_num(atollh(yytext)); + YY_BREAK +case 12: +YY_RULE_SETUP +#line 31 "yas-grammar.lex" +add_punct(*yytext); + YY_BREAK +case 13: +YY_RULE_SETUP +#line 32 "yas-grammar.lex" +add_ident(yytext); + YY_BREAK +case 14: +YY_RULE_SETUP +#line 33 "yas-grammar.lex" +{; BEGIN ERR;} + YY_BREAK +case 15: +/* rule 15 can match eol */ +YY_RULE_SETUP +#line 34 "yas-grammar.lex" +{fail("Invalid line"); lineno++; BEGIN 0;} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 35 "yas-grammar.lex" +ECHO; + YY_BREAK +#line 1111 "lex.yy.c" + case YY_STATE_EOF(INITIAL): + case YY_STATE_EOF(ERR): + case YY_STATE_EOF(COM): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); + + (yy_state_ptr) = (yy_state_buf); + *(yy_state_ptr)++ = yy_current_state; + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 257 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + *(yy_state_ptr)++ = yy_current_state; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + + YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 257 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 256); + if ( ! yy_is_jam ) + *(yy_state_ptr)++ = yy_current_state; + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp ) +{ + char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = (yy_n_chars) + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + + (yy_state_buf) = 0; + (yy_state_ptr) = 0; + (yy_full_match) = 0; + (yy_lp) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + yyfree ( (yy_state_buf) ); + (yy_state_buf) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 35 "yas-grammar.lex" + + +unsigned int atoh(const char *s) +{ + return(strtoul(s, NULL, 16)); +} + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.lex b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.lex new file mode 100644 index 00000000..be03756c --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.lex @@ -0,0 +1,39 @@ +/* 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;} +{Char}*{Newline} {fail("Invalid line"); lineno++; BEGIN 0;} +%% + +unsigned int atoh(const char *s) +{ + return(strtoul(s, NULL, 16)); +} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.o b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.o new file mode 100644 index 00000000..83b19e62 Binary files /dev/null and b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas-grammar.o differ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.c new file mode 100644 index 00000000..f36b1b6a --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.c @@ -0,0 +1,628 @@ +/* Assembler for Y86-64 instruction set */ + +#include +#include +#include + +#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 | + 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 | + where HHH is address + cccccccccccccccccccc is code + */ + if (tcount) { + int i; + if (pos > 0xFFF) { + fail("Code address limit exceeded"); + exit(1); + } + strcpy(outstring, "0x000: | "); + hexstuff(outstring+2, pos, 3); + for (i = 0; i < bcount; i++) + hexstuff(outstring+7+2*i, code[i]&0xFF, 2); + } + else + strcpy(outstring, " | "); + } + if (vcode) { + fprintf(out, "//%s%s\n", outstring, input_line); + if (tcount) { + int i; + for (i = 0; tcount && i < bcount; i++) { + if (block_factor) { + fprintf(out, " bank%d[%d] = 8\'h%.2x;\n", (pos+i)%block_factor, (pos+i)/block_factor, code[i] & 0xFF); + } else { + fprintf(out, " mem[%d] = 8\'h%.2x;\n", pos+i, code[i] & 0xFF); + } + } + } + } else { + fprintf(out, "%s%s\n", outstring, input_line); + } +} + +void fail(char *message) +{ + if (!error_mode) { + fprintf(stderr, "Error on line %d: %s\n", lineno, message); + fprintf(stderr, "Line %d, Byte 0x%.4x: %s\n", + lineno, bytepos, input_line); + } + error_mode = 1; + hit_error = 1; +} + +/* Parse Register from set of tokens and put into high or low + 4 bits of code[codepos] */ +void get_reg(int codepos, int hi) +{ + int rval = REG_NONE; + char c; + if (tokens[tpos].type != TOK_REG) { + fail("Expecting Register ID"); + return; + } else { + rval = find_register(tokens[tpos].sval); + } + /* Insert into output */ + c = code[codepos]; + if (hi) + c = (c & 0x0F) | (rval << 4); + else + c = (c & 0xF0) | rval; + code[codepos] = c; + tpos++; +} + +/* Get numeric value of given number of bytes */ +/* Offset indicates value to subtract from number (for PC relative) */ +void get_num(int codepos, int bytes, int offset) +{ + word_t val = 0; + int i; + if (tokens[tpos].type == TOK_NUM) { + val = tokens[tpos].ival; + } else if (tokens[tpos].type == TOK_IDENT) { + val = find_symbol(tokens[tpos].sval); + } else { + fail("Number Expected"); + return; + } + val -= offset; + for (i = 0; i < bytes; i++) + code[codepos+i] = (val >> (i * 8)) & 0xFF; + tpos++; +} + + +/* Get memory reference. + Can be of form: + Num(Reg) + (Reg) + Num + Ident + Ident(Reg) + Put Reg in low position of current byte, and Number in following bytes + */ +void get_mem(int codepos) +{ + char rval = REG_NONE; + word_t val = 0; + int i; + char c; + token_t type = tokens[tpos].type; + /* Deal with optional displacement */ + if (type == TOK_NUM) { + val = tokens[tpos++].ival; + type = tokens[tpos].type; + } else if (type == TOK_IDENT) { + val = find_symbol(tokens[tpos++].sval); + type = tokens[tpos].type; + } + /* Check for optional register */ + if (type == TOK_PUNCT) { + if (tokens[tpos].cval == '(') { + tpos++; + if (tokens[tpos].type == TOK_REG) + rval = find_register(tokens[tpos++].sval); + else { + fail("Expecting Register Id"); + return; + } + if (tokens[tpos].type != TOK_PUNCT || + tokens[tpos++].cval != ')') { + fail("Expecting ')'"); + return; + } + } + } + c = (code[codepos] & 0xF0) | (rval & 0xF); + code[codepos++] = c; + for (i = 0; i < 8; i++) + code[codepos+i] = (val >> (i*8)) & 0xFF; +} + +void start_line() +{ + int t; + error_mode = 0; + tpos = 0; + tcount = 0; + bcount = 0; + strpos = 0; + for (t = 0; t < TOK_PER_LINE; t++) + tokens[t].type = TOK_ERR; +} + +void finish_line() +{ + int size; + instr_ptr instr; + int savebytepos = bytepos; + tpos = 0; + codepos = 0; + if (tcount == 0) { + if (pass > 1) + print_code(outfile, savebytepos); + start_line(); + return; /* Empty line */ + } + /* Completion of an erroneous line */ + if (error_mode) { + start_line(); + return; + } + + /* See if this is a labeled line */ + if (tokens[0].type == TOK_IDENT) { + if (tokens[1].type != TOK_PUNCT || + tokens[1].cval != ':') { + fail("Missing Colon"); + start_line(); + return; + } else { + if (pass == 1) + add_symbol(tokens[0].sval, bytepos); + tpos+=2; + if (tcount == 2) { + /* That's all for this line */ + if (pass > 1) + print_code(outfile, savebytepos); + start_line(); + return; + } + } + } + /* Get instruction */ + if (tokens[tpos].type != TOK_INSTR) { + fail("Bad Instruction"); + start_line(); + return; + } + /* Process .pos */ + if (strcmp(tokens[tpos].sval, ".pos") == 0) { + if (tokens[++tpos].type != TOK_NUM) { + fail("Invalid Address"); + start_line(); + return; + } + bytepos = tokens[tpos].ival; + if (pass > 1) { + print_code(outfile, bytepos); + } + start_line(); + return; + } + /* Process .align */ + if (strcmp(tokens[tpos].sval, ".align") == 0) { + int a; + if (tokens[++tpos].type != TOK_NUM || (a=tokens[tpos].ival) <= 0) { + fail("Invalid Alignment"); + start_line(); + return; + } + bytepos = ((bytepos+a-1)/a)*a; + + if (pass > 1) { + print_code(outfile, bytepos); + } + start_line(); + return; + } + /* Get instruction size */ + instr = find_instr(tokens[tpos++].sval); + if (instr == NULL) { + fail("Invalid Instruction"); + instr = bad_instr(); + } + size = instr->bytes; + bytepos += size; + bcount = size; + + + /* If this is pass 1, then we're done */ + if (pass == 1) { + start_line(); + return; + } + + /* Here's where we really process the instructions */ + code[0] = instr->code; + code[1] = HPACK(REG_NONE, REG_NONE); + switch(instr->arg1) { + case R_ARG: + get_reg(instr->arg1pos, instr->arg1hi); + break; + case M_ARG: + get_mem(instr->arg1pos); + break; + case I_ARG: + get_num(instr->arg1pos, instr->arg1hi, 0); + break; + case NO_ARG: + default: + break; + } + if (instr->arg2 != NO_ARG) { + /* Get comma */ + if (tokens[tpos].type != TOK_PUNCT || + tokens[tpos].cval != ',') { + fail("Expecting Comma"); + start_line(); + return; + } + tpos++; + + /* Get second argument */ + switch(instr->arg2) { + case R_ARG: + get_reg(instr->arg2pos, instr->arg2hi); + break; + case M_ARG: + get_mem(instr->arg2pos); + break; + case I_ARG: + get_num(instr->arg2pos, instr->arg2hi, 0); + break; + case NO_ARG: + default: + break; + } + } + + print_code(outfile, savebytepos); + start_line(); +} + +void add_token(token_t type, char *s, word_t i, char c) +{ + char *t = NULL; + if (!tcount) + start_line(); + if (tpos >= TOK_PER_LINE-1) { + fail("Line too long"); + return; + } + if (s) { + int len = strlen(s)+1; + if (strpos + len > STRMAX) { + fail("Line too long"); + return; + } + t = strcpy(strbuf+strpos, s); + strpos+= len; + } + tokens[tcount].type = type; + tokens[tcount].sval = t; + tokens[tcount].ival = i; + tokens[tcount].cval = c; + tcount++; +} + +void add_ident(char *s) +{ + add_token(TOK_IDENT, s, 0, ' '); +} + +void add_instr(char *s) +{ + add_token(TOK_INSTR, s, 0, ' '); +} + +void add_reg(char *s) +{ + add_token(TOK_REG, s, 0, ' '); +} + +void add_num(long long i) +{ + add_token(TOK_NUM, NULL, i, ' '); +} + +void add_punct(char c) +{ + add_token(TOK_PUNCT, NULL, 0, c); +} + +#define STAB 1000 + +#define INIT_CNT 0 + +int symbol_cnt = INIT_CNT; +struct { + char *name; + int pos; +} symbol_table[STAB]; + +void add_symbol(char *name, int p) +{ + char *t = (char *) malloc(strlen(name)+1); + strcpy(t, name); + symbol_table[symbol_cnt].name = t; + symbol_table[symbol_cnt].pos = p; + symbol_cnt++; +} + +int find_symbol(char *name) +{ + int i; + for (i = 0; i < symbol_cnt; i++) + if (strcmp(name, symbol_table[i].name) == 0) + return symbol_table[i].pos; + fail("Can't find label"); + return -1; +} + +int yywrap() +{ + int i; + if (tcount > 0) { + fail("Missing end-of-line on final line\n"); + } + if (verbose && pass > 1) { + printf("Symbol Table:\n"); + for (i = INIT_CNT; i < symbol_cnt; i++) + printf(" %s\t0x%x\n", symbol_table[i].name, symbol_table[i].pos); + } + return 1; +} + +extern FILE *yyin; +int yylex(); + +static void usage(char *pname) +{ + printf("Usage: %s [-V[n]] file.ys\n", pname); + printf(" -V[n] Generate memory initialization in Verilog format (n-way blocking)\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + int rootlen; + char infname[512]; + char outfname[512]; + int nextarg = 1; + if (argc < 2) + usage(argv[0]); + if (argv[nextarg][0] == '-') { + char flag = argv[nextarg][1]; + switch (flag) { + case 'V': + vcode = 1; + if (argv[nextarg][2]) { + block_factor = atoi(argv[nextarg]+2); + if (block_factor != 8) { + fprintf(stderr, "Unknown blocking factor %d\n", block_factor); + exit(1); + } + } + nextarg++; + break; + default: + usage(argv[0]); + } + } + rootlen = strlen(argv[nextarg])-3; + if (strcmp(argv[nextarg]+rootlen, ".ys")) + usage(argv[0]); + if (rootlen > 500) { + fprintf(stderr, "File name too long\n"); + exit(1); + } + strncpy(infname, argv[nextarg], rootlen); + strcpy(infname+rootlen, ".ys"); + + yyin = fopen(infname, "r"); + if (!yyin) { + fprintf(stderr, "Can't open input file '%s'\n", infname); + exit(1); + } + + if (vcode) { + outfile = stdout; + } else { + strncpy(outfname, argv[nextarg], rootlen); + strcpy(outfname+rootlen, ".yo"); + outfile = fopen(outfname, "w"); + if (!outfile) { + fprintf(stderr, "Can't open output file '%s'\n", outfname); + exit(1); + } + } + + pass = 1; + + yylex(); + fclose(yyin); + + if (hit_error) + exit(1); + + pass = 2; + lineno = 1; + error_mode = 0; + bytepos = 0; + yyin = fopen(infname, "r"); + if (!yyin) { + fprintf(stderr, "Can't open input file '%s'\n", infname); + exit(1); + } + + yylex(); + fclose(yyin); + fclose(outfile); + return hit_error; +} + +unsigned long long atollh(const char *p) { + return strtoull(p, (char **) NULL, 16); +} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.h new file mode 100644 index 00000000..edbf6ff4 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.h @@ -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; diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.o b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.o new file mode 100644 index 00000000..6d4a621b Binary files /dev/null and b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yas.o differ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis new file mode 100755 index 00000000..9618b7da Binary files /dev/null and b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis differ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis.c new file mode 100644 index 00000000..88e49d12 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis.c @@ -0,0 +1,64 @@ +/* Instruction set simulator for Y86-64 Architecture */ + +#include +#include + +#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; +} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis.o b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis.o new file mode 100644 index 00000000..dccd7f1e Binary files /dev/null and b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/misc/yis.o differ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/Makefile b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/Makefile new file mode 100644 index 00000000..a1d6e4aa --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/Makefile @@ -0,0 +1,63 @@ +# Modify this line to indicate the default version to build + +VERSION=std + +# Comment this out if you don't have Tcl/Tk on your system + +GUIMODE= + +# 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= + +# 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= + +# Modify these two lines to choose your compiler and compile time +# flags. + +CC=gcc +CFLAGS=-Wall -O1 -g -fcommon -Wno-error + +################################################## +# 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 *~ + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/README b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/README new file mode 100644 index 00000000..f7ffb5a3 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/README @@ -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 + + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/benchmark.pl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/benchmark.pl new file mode 100755 index 00000000..51a41e61 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/benchmark.pl @@ -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 = 7.5; +# What CPE is required to get nonzero credit: +$threshcpe = 10.5; + + + +# +# usage - Print the help message and terminate +# +sub usage { + print STDERR "Usage: $0 [-hq] [-n N] -f FILE\n"; + print STDERR " -h Print help message\n"; + print STDERR " -q Quiet mode (default verbose)\n"; + print STDERR " -n N Set max number of elements up to 64 (default $blocklen)\n"; + print STDERR " -f FILE Input .ys file is FILE\n"; + die "\n"; +} + +getopts('hqn:f:'); + +if ($opt_h) { + usage(); +} + +if ($opt_q) { + $verbose = 0; +} + +if ($opt_n) { + $blocklen = $opt_n; + if ($blocklen < 0 || $blocklen > 64) { + print STDERR "n must be between 0 and 64\n"; + die "\n"; + } +} + +# Filename is required +if (!$opt_f) { + $ncopy = "ncopy"; +} else { + $ncopy = $opt_f; + # Strip off .ys + $ncopy =~ s/\.ys//; +} + +if ($verbose) { + print "\t$ncopy\n"; +} + +$tcpe = 0; +for ($i = 0; $i <= $blocklen; $i++) { + !(system "$gendriver -n $i -f $ncopy.ys > $fname$i.ys") || + die "Couldn't generate driver file $fname$i.ys\n"; + !(system "$yas $fname$i.ys") || + die "Couldn't assemble file $fname$i.ys\n"; + $stat = `$pipe -v 0 $fname$i.yo` || + die "Couldn't simulate file $fname$i.yo\n"; + !(system "rm $fname$i.ys $fname$i.yo") || + die "Couldn't remove files $fname$i.ys and/or $fname$i.yo\n"; + chomp $stat; + $stat =~ s/[ ]*CPI:[ ]*//; + $stat =~ s/ cycles.*//; + if ($i > 0) { + $cpe = $stat/$i; + if ($verbose) { + printf "%d\t%d\t%.2f\n", $i, $stat, $cpe; + } + $tcpe += $cpe; + } else { + if ($verbose) { + printf "%d\t%d\n", $i, $stat; + } + } + +} + +$acpe = $tcpe/$blocklen; +printf "Average CPE\t%.2f\n", $acpe; + +## Compute Score +$score = 0; +if ($acpe <= $fullcpe) { + $score = $totalpoints; +} elsif ($acpe <= $threshcpe) { + $score = $totalpoints * ($threshcpe - $acpe)/($threshcpe - $fullcpe); +} +printf "Score\t%.1f/%.1f\n", $score, $totalpoints; + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/check-len.pl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/check-len.pl new file mode 100755 index 00000000..63adff58 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/check-len.pl @@ -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"; +} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/correctness.pl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/correctness.pl new file mode 100755 index 00000000..bba36ca4 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/correctness.pl @@ -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; + last; + } + if ($stat =~ "dddd") { + $result = "Incorrect copying"; + } + if ($stat =~ "eeee") { + $result = "Corruption before or after destination"; + } + if ($verbose) { + printf "%d\t%s\n", $len, $result; + } +} + +$bp1 = $blocklen+$over+1; +printf "$goodcnt/$bp1 pass correctness test\n"; + + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/gen-driver.pl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/gen-driver.pl new file mode 100755 index 00000000..d2fff166 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/gen-driver.pl @@ -0,0 +1,247 @@ +#!/usr/bin/perl +#!/usr/local/bin/perl + +# +# gen-driver - Generate driver file for any ncopy function +# +use Getopt::Std; + +$n = 0; + +getopts('hcrn:f:b:'); + +if ($opt_h) { + print STDERR "Usage $argv[0] [-h] [-c] [-n N] [-f FILE]\n"; + print STDERR " -h print help message\n"; + print STDERR " -c include correctness checking code\n"; + print STDERR " -n N set number of elements\n"; + print STDERR " -f FILE set input file (default stdin)\n"; + print STDERR " -b blim set byte limit for function\n"; + print STDERR " -r Allow random result\n"; + die "\n"; +} + +$check = 0; +if ($opt_c) { + $check = 1; +} + +$bytelim = 1000; +if ($opt_b) { + $bytelim = $opt_b; +} + +if ($opt_n) { + $n = $opt_n; + if ($n < 0) { + print STDERR "n must be at least 0\n"; + die "\n"; + } +} + +$randomval = 0; +# Accumulated count +$rval = 0; + +if ($opt_r) { + $randomval = 1; +} else { + # Value that should be returned by function + $tval = int($n/2); +} + + +# The data to be stored. +@data = (); + +for ($i = 0; $i < $n; $i++) { + $data[$i] = -($i+1); + if ($randomval) { + if (int(rand(2)) == 1) { + $data[$i] = -$data[$i]; + $rval++; + } + } else { + if ($rval < $tval && int(rand(2)) % 2 == 1 || + $tval - $rval >= $n - $i) { + $data[$i] = -$data[$i]; + $rval++; + } + } +} + + +# Values to put at beginning and end of destination +$Preval = "0xbcdefa"; +$Postval = "0xdefabc"; + + +print <) { + printf "%s", $_; + } +} else { + while (<>) { + printf "%s", $_; + } +} +print "EndFun:\n"; + +if ($check) { +print < + +typedef word_t word_t; + +word_t src[8], dst[8]; + +/* $begin ncopy */ +/* + * ncopy - copy src to dst, returning number of positive ints + * contained in src array. + */ +word_t ncopy(word_t *src, word_t *dst, word_t len) +{ + word_t count = 0; + word_t val; + + while (len > 0) { + val = *src++; + *dst++ = val; + if (val > 0) + count++; + len--; + } + return count; +} +/* $end ncopy */ + +int main() +{ + word_t i, count; + + for (i=0; i<8; i++) + src[i]= i+1; + count = ncopy(src, dst, 8); + printf ("count=%d\n", count); + exit(0); +} + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/ncopy.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/ncopy.ys new file mode 100644 index 00000000..edc1c0de --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/ncopy.ys @@ -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: + irmovq $1, %r10 + addq %r10, %rax # count++ +Npos: irmovq $1, %r10 + subq %r10, %rdx # len-- + irmovq $8, %r10 + addq %r10, %rdi # src++ + addq %r10, %rsi # dst++ + andq %rdx,%rdx # len > 0? + jg Loop # if so, goto Loop: +################################################################## +# Do not modify the following section of code +# Function epilogue. +Done: + ret +################################################################## +# Keep the following label at the end of your function +End: +#/* $end ncopy-ys */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-1w.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-1w.hcl new file mode 100644 index 00000000..a1f76e12 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-1w.hcl @@ -0,0 +1,393 @@ +#/* $begin pipe-all-hcl */ +#################################################################### +# HCL Description of Control for Pipelined Y86-64 Processor # +# Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # +#################################################################### + +## Your task is to modify the design so that on any cycle, only +## one of the two possible (valE and valM) register writes will occur. +## This requires special handling of the popq instruction. +## Overall strategy: IPOPQ passes through pipe, +## treated as stack pointer increment, but not incrementing the PC +## On refetch, modify fetched icode to indicate an instruction "IPOP2", +## which reads from memory. +## This requires modifying the definition of f_icode +## and lots of other changes. Relevant positions to change +## are indicated by comments starting with keyword "1W". + +#################################################################### +# C Include's. Don't alter these # +#################################################################### + +quote '#include ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' +# 1W: Special instruction code for second try of popq +wordsig IPOP2 'I_POP2' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +## 1W: Provide access to the PC value for the current instruction +wordsig f_pc 'f_pc' # Address of fetched instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +## 1W: To split ipopq into two cycles, need to be able to +## modify value of icode, +## so that it will be IPOP2 when fetched for second time. +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + f_icode in { IJXX, ICALL } : f_valC; + ## 1W: Want to refetch popq one time + 1 : f_valP; +]; + +################ Decode Stage ###################################### + +## W1: Strategy. Decoding of popq rA should be treated the same +## as would iaddq $8, %rsp +## Decoding of pop2 rA treated same as mrmovq -8(%rsp), rA + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## Forward into decode stage for valA +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + d_srcA == e_dstE : e_valE; # Forward valE from execute + d_srcA == M_dstM : m_valM; # Forward valM from memory + d_srcA == M_dstE : M_valE; # Forward valE from memory + d_srcA == W_dstM : W_valM; # Forward valM from write back + d_srcA == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalA; # Use value read from register file +]; + +word d_valB = [ + d_srcB == e_dstE : e_valE; # Forward valE from execute + d_srcB == M_dstM : m_valM; # Forward valM from memory + d_srcB == M_dstE : M_valE; # Forward valE from memory + d_srcB == W_dstM : W_valM; # Forward valM from write back + d_srcB == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalB; # Use value read from register file +]; + +################ Execute Stage ##################################### + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +word e_valA = E_valA; # Pass valA through stage + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +################ Write back stage ################################## + +## 1W: For this problem, we introduce a multiplexor that merges +## valE and valM into a single value for writing to register port E. +## DO NOT CHANGE THIS LOGIC +## Merge both write back sources onto register port E +## Set E port register ID +word w_dstE = [ + ## writing from valM + W_dstM != RNONE : W_dstM; + 1: W_dstE; +]; + +## Set E port value +word w_valE = [ + W_dstM != RNONE : W_valM; + 1: W_valE; +]; + +## Disable register port M +## Set M port register ID +word w_dstM = RNONE; + +## Set M port value +word w_valM = 0; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB } || + # Stalling at fetch while ret passes through pipeline + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB }; + +bool D_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Stalling at fetch while ret passes through pipeline + # but not condition for a load/use hazard + !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && + # 1W: This condition will change + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB}; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-broken.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-broken.hcl new file mode 100644 index 00000000..eac6a61d --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-broken.hcl @@ -0,0 +1,331 @@ +#/* $begin pipe-all-hcl */ +#################################################################### +# HCL Description of Control for Pipelined Y86-64 Processor # +# Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # +#################################################################### +## This version does not detect or handle any hazards + +#################################################################### +# C Include's. Don't alter these # +#################################################################### + +quote '#include ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + f_icode in { IJXX, ICALL } : f_valC; + 1 : f_valP; +]; + +################ Decode Stage ###################################### + + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## No forwarding. valA is either valP or value from register file +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + 1 : d_rvalA; # Use value read from register file +]; + +## No forwarding. valB is value from register file +word d_valB = d_rvalB; + +################ Execute Stage ##################################### + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +word e_valA = E_valA; # Pass valA through stage + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +## Set E port register ID +word w_dstE = W_dstE; + +## Set E port value +word w_valE = W_valE; + +## Set M port register ID +word w_dstM = W_dstM; + +## Set M port value +word w_valM = W_valM; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + 0; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + 0; + +bool D_bubble = + 0; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + 0; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-btfnt.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-btfnt.hcl new file mode 100644 index 00000000..bbf3ebf6 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-btfnt.hcl @@ -0,0 +1,373 @@ +#/* $begin pipe-all-hcl */ +#################################################################### +# HCL Description of Control for Pipelined Y86-64 Processor # +# Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # +#################################################################### + +## Your task is to modify the design so that conditional branches are +## predicted as being taken when backward and not-taken when forward +## The code here is nearly identical to that for the normal pipeline. +## Comments starting with keyword "BBTFNT" have been added at places +## relevant to the exercise. + +#################################################################### +# C Include's. Don't alter these # +#################################################################### + +quote '#include ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments +## BBTFNT: For modified branch prediction, need to distinguish +## conditional vs. unconditional branches +##### Jump conditions referenced explicitly +wordsig UNCOND 'C_YES' # Unconditional transfer + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + # BBTFNT: This is where you'll change the branch prediction rule + f_icode in { IJXX, ICALL } : f_valC; + 1 : f_valP; +]; + +################ Decode Stage ###################################### + + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## Forward into decode stage for valA +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + d_srcA == e_dstE : e_valE; # Forward valE from execute + d_srcA == M_dstM : m_valM; # Forward valM from memory + d_srcA == M_dstE : M_valE; # Forward valE from memory + d_srcA == W_dstM : W_valM; # Forward valM from write back + d_srcA == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalA; # Use value read from register file +]; + +word d_valB = [ + d_srcB == e_dstE : e_valE; # Forward valE from execute + d_srcB == M_dstM : m_valM; # Forward valM from memory + d_srcB == M_dstE : M_valE; # Forward valE from memory + d_srcB == W_dstM : W_valM; # Forward valM from write back + d_srcB == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalB; # Use value read from register file +]; + +################ Execute Stage ##################################### + +# BBTFNT: When some branches are predicted as not-taken, you need some +# way to get valC into pipeline register M, so that +# you can correct for a mispredicted branch. + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +word e_valA = E_valA; # Pass valA through stage + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +## Set E port register ID +word w_dstE = W_dstE; + +## Set E port value +word w_valE = W_valE; + +## Set M port register ID +word w_dstM = W_dstM; + +## Set M port value +word w_valM = W_valM; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB } || + # Stalling at fetch while ret passes through pipeline + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB }; + +bool D_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # BBTFNT: This condition will change + # Stalling at fetch while ret passes through pipeline + # but not condition for a load/use hazard + !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # BBTFNT: This condition will change + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB}; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-full.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-full.hcl new file mode 100644 index 00000000..837eb49e --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-full.hcl @@ -0,0 +1,363 @@ +#/* $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 ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' +# Instruction code for iaddq instruction +wordsig IIADDQ 'I_IADDQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + f_icode in { IJXX, ICALL } : f_valC; + 1 : f_valP; +]; + +################ Decode Stage ###################################### + + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## Forward into decode stage for valA +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + d_srcA == e_dstE : e_valE; # Forward valE from execute + d_srcA == M_dstM : m_valM; # Forward valM from memory + d_srcA == M_dstE : M_valE; # Forward valE from memory + d_srcA == W_dstM : W_valM; # Forward valM from write back + d_srcA == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalA; # Use value read from register file +]; + +word d_valB = [ + d_srcB == e_dstE : e_valE; # Forward valE from execute + d_srcB == M_dstM : m_valM; # Forward valM from memory + d_srcB == M_dstE : M_valE; # Forward valE from memory + d_srcB == W_dstM : W_valM; # Forward valM from write back + d_srcB == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalB; # Use value read from register file +]; + +################ Execute Stage ##################################### + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +word e_valA = E_valA; # Pass valA through stage + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +## Set E port register ID +word w_dstE = W_dstE; + +## Set E port value +word w_valE = W_valE; + +## Set M port register ID +word w_dstM = W_dstM; + +## Set M port value +word w_valM = W_valM; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB } || + # Stalling at fetch while ret passes through pipeline + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB }; + +bool D_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Stalling at fetch while ret passes through pipeline + # but not condition for a load/use hazard + !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB}; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-lf.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-lf.hcl new file mode 100644 index 00000000..92086dd2 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-lf.hcl @@ -0,0 +1,370 @@ +#/* $begin pipe-all-hcl */ +#################################################################### +# HCL Description of Control for Pipelined Y86-64 Processor # +# Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # +#################################################################### + +## Your task is to implement load-forwarding, where a value +## read from memory can be stored to memory by the immediately +## following instruction without stalling +## This requires modifying the definition of e_valA +## and relaxing the stall conditions. Relevant sections to change +## are shown in comments containing the keyword "LB" + +#################################################################### +# C Include's. Don't alter these # +#################################################################### + +quote '#include ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory +## LF: Carry srcA up to pipeline register M +wordsig M_srcA 'ex_mem_curr->srca' # Source A register ID + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + f_icode in { IJXX, ICALL } : f_valC; + 1 : f_valP; +]; + +################ Decode Stage ###################################### + + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## Forward into decode stage for valA +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + d_srcA == e_dstE : e_valE; # Forward valE from execute + d_srcA == M_dstM : m_valM; # Forward valM from memory + d_srcA == M_dstE : M_valE; # Forward valE from memory + d_srcA == W_dstM : W_valM; # Forward valM from write back + d_srcA == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalA; # Use value read from register file +]; + +word d_valB = [ + d_srcB == e_dstE : e_valE; # Forward valE from execute + d_srcB == M_dstM : m_valM; # Forward valM from memory + d_srcB == M_dstE : M_valE; # Forward valE from memory + d_srcB == W_dstM : W_valM; # Forward valM from write back + d_srcB == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalB; # Use value read from register file +]; + +################ Execute Stage ##################################### + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +## LB: With load forwarding, want to insert valM +## from memory stage when appropriate +## Here it is set to the default used in the normal pipeline +word e_valA = [ + 1 : E_valA; # Use valA from stage pipe register +]; + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +## Set E port register ID +word w_dstE = W_dstE; + +## Set E port value +word w_valE = W_valE; + +## Set M port register ID +word w_dstM = W_dstM; + +## Set M port value +word w_valM = W_valM; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + # Conditions for a load/use hazard + ## Set this to the new load/use condition + 0 || + # Stalling at fetch while ret passes through pipeline + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + # Conditions for a load/use hazard + ## Set this to the new load/use condition + 0; + +bool D_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Stalling at fetch while ret passes through pipeline + # but not condition for a load/use hazard + !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Conditions for a load/use hazard + ## Set this to the new load/use condition + 0; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-nobypass.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-nobypass.hcl new file mode 100644 index 00000000..605258b8 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-nobypass.hcl @@ -0,0 +1,349 @@ +#/* $begin pipe-all-hcl */ +#################################################################### +# HCL Description of Control for Pipelined Y86-64 Processor # +# Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # +#################################################################### + +## Your task is to make the pipeline work without using any forwarding +## The normal bypassing logic in the file is disabled. +## You can only change the pipeline control logic at the end of this file. +## The trick is to make the pipeline stall whenever there is a data hazard. + +#################################################################### +# C Include's. Don't alter these # +#################################################################### + +quote '#include ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + f_icode in { IJXX, ICALL } : f_valC; + 1 : f_valP; +]; + +################ Decode Stage ###################################### + + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## DO NOT MODIFY THE FOLLOWING CODE. +## No forwarding. valA is either valP or value from register file +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + 1 : d_rvalA; # Use value read from register file +]; + +## No forwarding. valB is value from register file +word d_valB = d_rvalB; + +################ Execute Stage ##################################### + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +word e_valA = E_valA; # Pass valA through stage + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +## Set E port register ID +word w_dstE = W_dstE; + +## Set E port value +word w_valE = W_valE; + +## Set M port register ID +word w_dstM = W_dstM; + +## Set M port value +word w_valM = W_valM; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + # Modify the following to stall the update of pipeline register F + 0 || + # Stalling at fetch while ret passes through pipeline + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + # Modify the following to stall the instruction in decode + 0; + +bool D_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Stalling at fetch while ret passes through pipeline + !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && + # but not condition for a generate/use hazard + !0 && + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Modify the following to inject bubble into the execute stage + 0; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-nt.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-nt.hcl new file mode 100644 index 00000000..d5b2abba --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-nt.hcl @@ -0,0 +1,371 @@ +#/* $begin pipe-all-hcl */ +#################################################################### +# HCL Description of Control for Pipelined Y86-64 Processor # +# Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # +#################################################################### + +## Your task is to modify the design so that conditional branches are +## predicted as being not-taken. The code here is nearly identical +## to that for the normal pipeline. +## Comments starting with keyword "BNT" have been added at places +## relevant to the exercise. + +#################################################################### +# C Include's. Don't alter these # +#################################################################### + +quote '#include ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments +## BNT: For modified branch prediction, need to distinguish +## conditional vs. unconditional branches +##### Jump conditions referenced explicitly +wordsig UNCOND 'C_YES' # Unconditional transfer + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + # BNT: This is where you'll change the branch prediction rule + f_icode in { IJXX, ICALL } : f_valC; + 1 : f_valP; +]; + +################ Decode Stage ###################################### + + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## Forward into decode stage for valA +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + d_srcA == e_dstE : e_valE; # Forward valE from execute + d_srcA == M_dstM : m_valM; # Forward valM from memory + d_srcA == M_dstE : M_valE; # Forward valE from memory + d_srcA == W_dstM : W_valM; # Forward valM from write back + d_srcA == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalA; # Use value read from register file +]; + +word d_valB = [ + d_srcB == e_dstE : e_valE; # Forward valE from execute + d_srcB == M_dstM : m_valM; # Forward valM from memory + d_srcB == M_dstE : M_valE; # Forward valE from memory + d_srcB == W_dstM : W_valM; # Forward valM from write back + d_srcB == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalB; # Use value read from register file +]; + +################ Execute Stage ##################################### + +# BNT: When some branches are predicted as not-taken, you need some +# way to get valC into pipeline register M, so that +# you can correct for a mispredicted branch. + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +word e_valA = E_valA; # Pass valA through stage + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +## Set E port register ID +word w_dstE = W_dstE; + +## Set E port value +word w_valE = W_valE; + +## Set M port register ID +word w_dstM = W_dstM; + +## Set M port value +word w_valM = W_valM; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB } || + # Stalling at fetch while ret passes through pipeline + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB }; + +bool D_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Stalling at fetch while ret passes through pipeline + # but not condition for a load/use hazard + !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB}; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-std.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-std.hcl new file mode 100644 index 00000000..1bc8ce87 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe-std.hcl @@ -0,0 +1,356 @@ +#/* $begin pipe-all-hcl */ +#################################################################### +# HCL Description of Control for Pipelined Y86-64 Processor # +# Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014 # +#################################################################### + +#################################################################### +# C Include's. Don't alter these # +#################################################################### + +quote '#include ' +quote '#include "isa.h"' +quote '#include "pipeline.h"' +quote '#include "stages.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ########################## +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SBUB 'STAT_BUB' # Bubble in stage +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic ############## + +##### Pipeline Register F ########################################## + +wordsig F_predPC 'pc_curr->pc' # Predicted value of PC + +##### Intermediate Values in Fetch Stage ########################### + +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig f_icode 'if_id_next->icode' # (Possibly modified) instruction code +wordsig f_ifun 'if_id_next->ifun' # Fetched instruction function +wordsig f_valC 'if_id_next->valc' # Constant data of fetched instruction +wordsig f_valP 'if_id_next->valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Pipeline Register D ########################################## +wordsig D_icode 'if_id_curr->icode' # Instruction code +wordsig D_rA 'if_id_curr->ra' # rA field from instruction +wordsig D_rB 'if_id_curr->rb' # rB field from instruction +wordsig D_valP 'if_id_curr->valp' # Incremented PC + +##### Intermediate Values in Decode Stage ######################### + +wordsig d_srcA 'id_ex_next->srca' # srcA from decoded instruction +wordsig d_srcB 'id_ex_next->srcb' # srcB from decoded instruction +wordsig d_rvalA 'd_regvala' # valA read from register file +wordsig d_rvalB 'd_regvalb' # valB read from register file + +##### Pipeline Register E ########################################## +wordsig E_icode 'id_ex_curr->icode' # Instruction code +wordsig E_ifun 'id_ex_curr->ifun' # Instruction function +wordsig E_valC 'id_ex_curr->valc' # Constant data +wordsig E_srcA 'id_ex_curr->srca' # Source A register ID +wordsig E_valA 'id_ex_curr->vala' # Source A value +wordsig E_srcB 'id_ex_curr->srcb' # Source B register ID +wordsig E_valB 'id_ex_curr->valb' # Source B value +wordsig E_dstE 'id_ex_curr->deste' # Destination E register ID +wordsig E_dstM 'id_ex_curr->destm' # Destination M register ID + +##### Intermediate Values in Execute Stage ######################### +wordsig e_valE 'ex_mem_next->vale' # valE generated by ALU +boolsig e_Cnd 'ex_mem_next->takebranch' # Does condition hold? +wordsig e_dstE 'ex_mem_next->deste' # dstE (possibly modified to be RNONE) + +##### Pipeline Register M ######################### +wordsig M_stat 'ex_mem_curr->status' # Instruction status +wordsig M_icode 'ex_mem_curr->icode' # Instruction code +wordsig M_ifun 'ex_mem_curr->ifun' # Instruction function +wordsig M_valA 'ex_mem_curr->vala' # Source A value +wordsig M_dstE 'ex_mem_curr->deste' # Destination E register ID +wordsig M_valE 'ex_mem_curr->vale' # ALU E value +wordsig M_dstM 'ex_mem_curr->destm' # Destination M register ID +boolsig M_Cnd 'ex_mem_curr->takebranch' # Condition flag +boolsig dmem_error 'dmem_error' # Error signal from instruction memory + +##### Intermediate Values in Memory Stage ########################## +wordsig m_valM 'mem_wb_next->valm' # valM generated by memory +wordsig m_stat 'mem_wb_next->status' # stat (possibly modified to be SADR) + +##### Pipeline Register W ########################################## +wordsig W_stat 'mem_wb_curr->status' # Instruction status +wordsig W_icode 'mem_wb_curr->icode' # Instruction code +wordsig W_dstE 'mem_wb_curr->deste' # Destination E register ID +wordsig W_valE 'mem_wb_curr->vale' # ALU E value +wordsig W_dstM 'mem_wb_curr->destm' # Destination M register ID +wordsig W_valM 'mem_wb_curr->valm' # Memory M value + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +## What address should instruction be fetched at +word f_pc = [ + # Mispredicted branch. Fetch at incremented PC + M_icode == IJXX && !M_Cnd : M_valA; + # Completion of RET instruction + W_icode == IRET : W_valM; + # Default: Use predicted value of PC + 1 : F_predPC; +]; + +## Determine icode of fetched instruction +word f_icode = [ + imem_error : INOP; + 1: imem_icode; +]; + +# Determine ifun +word f_ifun = [ + imem_error : FNONE; + 1: imem_ifun; +]; + +# Is instruction valid? +bool instr_valid = f_icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Determine status code for fetched instruction +word f_stat = [ + imem_error: SADR; + !instr_valid : SINS; + f_icode == IHALT : SHLT; + 1 : SAOK; +]; + +# Does fetched instruction require a regid byte? +bool need_regids = + f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +# Predict next value of PC +word f_predPC = [ + f_icode in { IJXX, ICALL } : f_valC; + 1 : f_valP; +]; + +################ Decode Stage ###################################### + + +## What register should be used as the A source? +word d_srcA = [ + D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : D_rA; + D_icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word d_srcB = [ + D_icode in { IOPQ, IRMMOVQ, IMRMOVQ } : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word d_dstE = [ + D_icode in { IRRMOVQ, IIRMOVQ, IOPQ} : D_rB; + D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word d_dstM = [ + D_icode in { IMRMOVQ, IPOPQ } : D_rA; + 1 : RNONE; # Don't write any register +]; + +## What should be the A value? +## Forward into decode stage for valA +word d_valA = [ + D_icode in { ICALL, IJXX } : D_valP; # Use incremented PC + d_srcA == e_dstE : e_valE; # Forward valE from execute + d_srcA == M_dstM : m_valM; # Forward valM from memory + d_srcA == M_dstE : M_valE; # Forward valE from memory + d_srcA == W_dstM : W_valM; # Forward valM from write back + d_srcA == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalA; # Use value read from register file +]; + +word d_valB = [ + d_srcB == e_dstE : e_valE; # Forward valE from execute + d_srcB == M_dstM : m_valM; # Forward valM from memory + d_srcB == M_dstE : M_valE; # Forward valE from memory + d_srcB == W_dstM : W_valM; # Forward valM from write back + d_srcB == W_dstE : W_valE; # Forward valE from write back + 1 : d_rvalB; # Use value read from register file +]; + +################ Execute Stage ##################################### + +## Select input A to ALU +word aluA = [ + E_icode in { IRRMOVQ, IOPQ } : E_valA; + E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : E_valC; + E_icode in { ICALL, IPUSHQ } : -8; + E_icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : E_valB; + E_icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + E_icode == IOPQ : E_ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = E_icode == IOPQ && + # State changes only during normal operation + !m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT }; + +## Generate valA in execute stage +word e_valA = E_valA; # Pass valA through stage + +## Set dstE to RNONE in event of not-taken conditional move +word e_dstE = [ + E_icode == IRRMOVQ && !e_Cnd : RNONE; + 1 : E_dstE; +]; + +################ Memory Stage ###################################### + +## Select memory address +word mem_addr = [ + M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE; + M_icode in { IPOPQ, IRET } : M_valA; + # Other instructions don't need address +]; + +## Set read control signal +bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL }; + +#/* $begin pipe-m_stat-hcl */ +## Update the status +word m_stat = [ + dmem_error : SADR; + 1 : M_stat; +]; +#/* $end pipe-m_stat-hcl */ + +## Set E port register ID +word w_dstE = W_dstE; + +## Set E port value +word w_valE = W_valE; + +## Set M port register ID +word w_dstM = W_dstM; + +## Set M port value +word w_valM = W_valM; + +## Update processor status +word Stat = [ + W_stat == SBUB : SAOK; + 1 : W_stat; +]; + +################ Pipeline Register Control ######################### + +# Should I stall or inject a bubble into Pipeline Register F? +# At most one of these can be true. +bool F_bubble = 0; +bool F_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB } || + # Stalling at fetch while ret passes through pipeline + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register D? +# At most one of these can be true. +bool D_stall = + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB }; + +bool D_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Stalling at fetch while ret passes through pipeline + # but not condition for a load/use hazard + !(E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB }) && + IRET in { D_icode, E_icode, M_icode }; + +# Should I stall or inject a bubble into Pipeline Register E? +# At most one of these can be true. +bool E_stall = 0; +bool E_bubble = + # Mispredicted branch + (E_icode == IJXX && !e_Cnd) || + # Conditions for a load/use hazard + E_icode in { IMRMOVQ, IPOPQ } && + E_dstM in { d_srcA, d_srcB}; + +# Should I stall or inject a bubble into Pipeline Register M? +# At most one of these can be true. +bool M_stall = 0; +# Start injecting bubbles as soon as exception passes through memory stage +bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT }; + +# Should I stall or inject a bubble into Pipeline Register W? +bool W_stall = W_stat in { SADR, SINS, SHLT }; +bool W_bubble = 0; +#/* $end pipe-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe.tcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe.tcl new file mode 100755 index 00000000..3129d6c5 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipe.tcl @@ -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} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipeline.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipeline.h new file mode 100644 index 00000000..61eb239d --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/pipeline.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * pipe.h + * + * Code for implementing pipelined processor simulators + ******************************************************************************/ + +#ifndef PIPE_H +#define PIPE_H + +/****************************************************************************** + * #includes + ******************************************************************************/ + +#include + +/****************************************************************************** + * 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 */ + + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/psim.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/psim.c new file mode 100644 index 00000000..c08508eb --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/psim.c @@ -0,0 +1,1604 @@ +/************************************************************************** + * psim.c - Pipelined Y86-64 simulator + * + * Copyright (c) 2010, 2015. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + **************************************************************************/ + +#include +#include +#include +#include +#include + +#include "isa.h" +#include "pipeline.h" +#include "stages.h" +#include "sim.h" + +#define MAXBUF 1024 +#define DEFAULTNAME "Y86-64 Simulator: " + +#ifdef HAS_GUI +#include +#endif /* HAS_GUI */ + +#define MAXARGS 128 +#define MAXBUF 1024 +#define TKARGS 3 + + +/*************** + * Begin Globals + ***************/ + +/* Simulator name defined and initialized by the compiled HCL file */ +/* according to the -n argument supplied to hcl2c */ +extern char simname[]; + +/* Parameters modifed by the command line */ +int gui_mode = FALSE; /* Run in GUI mode instead of TTY mode? (-g) */ +char *object_filename; /* The input object file name. */ +FILE *object_file; /* Input file handle */ +bool_t verbosity = 2; /* Verbosity level [TTY only] (-v) */ +word_t instr_limit = 10000; /* Instruction limit [TTY only] (-l) */ +bool_t do_check = FALSE; /* Test with ISA simulator? [TTY only] (-t) */ + +/************* + * End Globals + *************/ + + +/*************************** + * Begin function prototypes + ***************************/ + +word_t sim_run_pipe(word_t max_instr, word_t max_cycle, byte_t *statusp, cc_t *ccp); +static void usage(char *name); /* Print helpful usage message */ +static void run_tty_sim(); /* Run simulator in TTY mode */ + +#ifdef HAS_GUI +void addAppCommands(Tcl_Interp *interp); /* Add application-dependent commands */ +#endif /* HAS_GUI */ + +/************************* + * End function prototypes + *************************/ + + +/******************************************************************* + * Part 1: This part is the initial entry point that handles general + * initialization. It parses the command line and does any necessary + * setup to run in either TTY or GUI mode, and then starts the + * simulation. + *******************************************************************/ + +/* + * sim_main - main simulator routine. This function is called from the + * main() routine in the HCL file. + */ +int sim_main(int argc, char **argv) +{ + int i; + int c; + char *myargv[MAXARGS]; + + /* Parse the command line arguments */ + while ((c = getopt(argc, argv, "htgl:v:")) != -1) { + switch(c) { + case 'h': + usage(argv[0]); + break; + case 'l': + instr_limit = atoll(optarg); + break; + case 'v': + verbosity = atoi(optarg); + if (verbosity < 0 || verbosity > 2) { + printf("Invalid verbosity %d\n", verbosity); + usage(argv[0]); + } + break; + case 't': + do_check = TRUE; + break; + case 'g': + gui_mode = TRUE; + break; + default: + printf("Invalid option '%c'\n", c); + usage(argv[0]); + break; + } + } + + + /* Do we have too many arguments? */ + if (optind < argc - 1) { + printf("Too many command line arguments:"); + for (i = optind; i < argc; i++) + printf(" %s", argv[i]); + printf("\n"); + usage(argv[0]); + } + + + /* The single unflagged argument should be the object file name */ + object_filename = NULL; + object_file = NULL; + if (optind < argc) { + object_filename = argv[optind]; + object_file = fopen(object_filename, "r"); + if (!object_file) { + fprintf(stderr, "Couldn't open object file %s\n", object_filename); + exit(1); + } + } + + + /* Run the simulator in GUI mode (-g flag) */ + if (gui_mode) { + +#ifndef HAS_GUI + printf("To run in GUI mode, you must recompile with the HAS_GUI constant defined.\n"); + exit(1); +#endif /* HAS_GUI */ + + /* In GUI mode, we must specify the object file on command line */ + if (!object_file) { + printf("Missing object file argument in GUI mode\n"); + usage(argv[0]); + } + + /* Build the command line for the GUI simulator */ + for (i = 0; i < TKARGS; i++) { + if ((myargv[i] = malloc(MAXBUF*sizeof(char))) == NULL) { + perror("malloc error"); + exit(1); + } + } + strcpy(myargv[0], argv[0]); + strcpy(myargv[1], "pipe.tcl"); + strcpy(myargv[2], object_filename); + myargv[3] = NULL; + + /* Start the GUI simulator */ +#ifdef HAS_GUI + Tk_Main(TKARGS, myargv, Tcl_AppInit); +#endif /* HAS_GUI */ + exit(0); + } + + /* Otherwise, run the simulator in TTY mode (no -g flag) */ + run_tty_sim(); + + exit(0); +} + +/* + * run_tty_sim - Run the simulator in TTY mode + */ +static void run_tty_sim() +{ + word_t icount = 0; + byte_t run_status = STAT_AOK; + cc_t result_cc = 0; + word_t byte_cnt = 0; + mem_t mem0, reg0; + state_ptr isa_state = NULL; + + + /* In TTY mode, the default object file comes from stdin */ + if (!object_file) { + object_file = stdin; + } + + if (verbosity >= 2) + sim_set_dumpfile(stdout); + sim_init(); + + /* Emit simulator name */ + if (verbosity >= 2) + printf("%s\n", simname); + + byte_cnt = load_mem(mem, object_file, 1); + if (byte_cnt == 0) { + fprintf(stderr, "No lines of code found\n"); + exit(1); + } else if (verbosity >= 2) { + printf("%lld bytes of code read\n", byte_cnt); + } + fclose(object_file); + if (do_check) { + isa_state = new_state(0); + free_mem(isa_state->r); + free_mem(isa_state->m); + isa_state->m = copy_mem(mem); + isa_state->r = copy_mem(reg); + isa_state->cc = cc; + } + + mem0 = copy_mem(mem); + reg0 = copy_mem(reg); + + icount = sim_run_pipe(instr_limit, 5*instr_limit, &run_status, &result_cc); + if (verbosity > 0) { + printf("%lld instructions executed\n", icount); + printf("Status = %s\n", stat_name(run_status)); + printf("Condition Codes: %s\n", cc_name(result_cc)); + printf("Changed Register State:\n"); + diff_reg(reg0, reg, stdout); + printf("Changed Memory State:\n"); + diff_mem(mem0, mem, stdout); + } + if (do_check) { + byte_t e = STAT_AOK; + word_t step; + bool_t match = TRUE; + + for (step = 0; step < instr_limit && e == STAT_AOK; step++) { + e = step_state(isa_state, stdout); + } + + if (diff_reg(isa_state->r, reg, NULL)) { + match = FALSE; + if (verbosity > 0) { + printf("ISA Register != Pipeline Register File\n"); + diff_reg(isa_state->r, reg, stdout); + } + } + if (diff_mem(isa_state->m, mem, NULL)) { + match = FALSE; + if (verbosity > 0) { + printf("ISA Memory != Pipeline Memory\n"); + diff_mem(isa_state->m, mem, stdout); + } + } + if (isa_state->cc != result_cc) { + match = FALSE; + if (verbosity > 0) { + printf("ISA Cond. Codes (%s) != Pipeline Cond. Codes (%s)\n", + cc_name(isa_state->cc), cc_name(result_cc)); + } + } + if (match) { + printf("ISA Check Succeeds\n"); + } else { + printf("ISA Check Fails\n"); + } + } + + /* Emit CPI statistics */ + { + double cpi = instructions > 0 ? (double) cycles/instructions : 1.0; + printf("CPI: %lld cycles/%lld instructions = %.2f\n", + cycles, instructions, cpi); + } + +} + +/* + * usage - print helpful diagnostic information + */ +static void usage(char *name) +{ + printf("Usage: %s [-htg] [-l m] [-v n] file.yo\n", name); + printf("file.yo arg required in GUI mode, optional in TTY mode (default stdin)\n"); + printf(" -h Print this message\n"); + printf(" -g Run in GUI mode instead of TTY mode (default TTY)\n"); + printf(" -l m Set instruction limit to m [TTY mode only] (default %lld)\n", instr_limit); + printf(" -v n Set verbosity level to 0 <= n <= 2 [TTY mode only] (default %d)\n", verbosity); + printf(" -t Test result against ISA simulator [TTY mode only]\n"); + exit(0); +} + + +/********************************************************* + * Part 2: This part contains the core simulator routines. + *********************************************************/ + + +/***************** + * Part 2 Globals + *****************/ + +/* Performance monitoring */ +/* How many cycles have been simulated? */ +word_t cycles = 0; +/* How many instructions have passed through the WB stage? */ +word_t instructions = 0; + +/* Has simulator gotten past initial bubbles? */ +static int starting_up = 1; + + + +/* Both instruction and data memory */ +mem_t mem; +word_t minAddr = 0; +word_t memCnt = 0; + +/* Register file */ +mem_t reg; +/* Condition code register */ +cc_t cc; +/* Status code */ +stat_t status; + + +/* Pending updates to state */ +word_t cc_in = DEFAULT_CC; +word_t wb_destE = REG_NONE; +word_t wb_valE = 0; +word_t wb_destM = REG_NONE; +word_t wb_valM = 0; +word_t mem_addr = 0; +word_t mem_data = 0; +bool_t mem_write = FALSE; + +/* EX Operand sources */ +mux_source_t amux = MUX_NONE; +mux_source_t bmux = MUX_NONE; + +/* Current and next states of all pipeline registers */ +pc_ptr pc_curr; +if_id_ptr if_id_curr; +id_ex_ptr id_ex_curr; +ex_mem_ptr ex_mem_curr; +mem_wb_ptr mem_wb_curr; + +pc_ptr pc_next; +if_id_ptr if_id_next; +id_ex_ptr id_ex_next; +ex_mem_ptr ex_mem_next; +mem_wb_ptr mem_wb_next; + +/* Intermediate values */ +word_t f_pc; +byte_t imem_icode; +byte_t imem_ifun; +bool_t imem_error; +bool_t instr_valid; +word_t d_regvala; +word_t d_regvalb; +word_t e_vala; +word_t e_valb; +bool_t e_bcond; +bool_t dmem_error; + +/* The pipeline state */ +pipe_ptr pc_state, if_id_state, id_ex_state, ex_mem_state, mem_wb_state; + +/* Simulator operating mode */ +sim_mode_t sim_mode = S_FORWARD; +/* Log file */ +FILE *dumpfile = NULL; + +/***************************************************************************** + * reporting code + *****************************************************************************/ + +#ifdef HAS_GUI +/* used for formatting instructions */ +static char status_msg[128]; + +static char *format_pc(pc_ptr state) +{ + char pstring[17]; + wstring(state->pc, 4, 64, pstring); + sprintf(status_msg, "%s %s", stat_name(state->status), pstring); + return status_msg; +} + +static char *format_if_id(if_id_ptr state) +{ + char valcstring[17]; + char valpstring[17]; + wstring(state->valc, 4, 64, valcstring); + wstring(state->valp, 4, 64, valpstring); + sprintf(status_msg, "%s %s %s %s %s %s", + stat_name(state->status), + iname(HPACK(state->icode,state->ifun)), + reg_name(state->ra), + reg_name(state->rb), + valcstring, + valpstring); + return status_msg; +} + +static char *format_id_ex(id_ex_ptr state) +{ + char valcstring[17]; + char valastring[17]; + char valbstring[17]; + wstring(state->valc, 4, 64, valcstring); + wstring(state->vala, 4, 64, valastring); + wstring(state->valb, 4, 64, valbstring); + sprintf(status_msg, "%s %s %s %s %s %s %s %s %s", + stat_name(state->status), + iname(HPACK(state->icode, state->ifun)), + valcstring, + valastring, + valbstring, + reg_name(state->deste), + reg_name(state->destm), + reg_name(state->srca), + reg_name(state->srcb)); + return status_msg; +} + +static char *format_ex_mem(ex_mem_ptr state) +{ + char valestring[17]; + char valastring[17]; + wstring(state->vale, 4, 64, valestring); + wstring(state->vala, 4, 64, valastring); + sprintf(status_msg, "%s %s %c %s %s %s %s", + stat_name(state->status), + iname(HPACK(state->icode, state->ifun)), + state->takebranch ? 'Y' : 'N', + valestring, + valastring, + reg_name(state->deste), + reg_name(state->destm)); + + return status_msg; +} + +static char *format_mem_wb(mem_wb_ptr state) +{ + char valestring[17]; + char valmstring[17]; + wstring(state->vale, 4, 64, valestring); + wstring(state->valm, 4, 64, valmstring); + sprintf(status_msg, "%s %s %s %s %s %s", + stat_name(state->status), + iname(HPACK(state->icode, state->ifun)), + valestring, + valmstring, + reg_name(state->deste), + reg_name(state->destm)); + + return status_msg; +} +#endif /* HAS_GUI */ + +/* Report system state */ +static void sim_report() +{ + +#ifdef HAS_GUI + if (gui_mode) { + report_pc(f_pc, pc_curr->status != STAT_BUB, + if_id_curr->stage_pc, if_id_curr->status != STAT_BUB, + id_ex_curr->stage_pc, id_ex_curr->status != STAT_BUB, + ex_mem_curr->stage_pc, ex_mem_curr->status != STAT_BUB, + mem_wb_curr->stage_pc, mem_wb_curr->status != STAT_BUB); + report_state("F", 0, format_pc(pc_next)); + report_state("F", 1, format_pc(pc_curr)); + report_state("D", 0, format_if_id(if_id_next)); + report_state("D", 1, format_if_id(if_id_curr)); + report_state("E", 0, format_id_ex(id_ex_next)); + report_state("E", 1, format_id_ex(id_ex_curr)); + report_state("M", 0, format_ex_mem(ex_mem_next)); + report_state("M", 1, format_ex_mem(ex_mem_curr)); + report_state("W", 0, format_mem_wb(mem_wb_next)); + report_state("W", 1, format_mem_wb(mem_wb_curr)); + /* signal_sources(); */ + show_cc(cc); + show_stat(status); + show_cpi(); + } +#endif + +} + +/***************************************************************************** + * pipeline control + * These functions can be used to handle hazards + *****************************************************************************/ + +/* bubble stage (has effect at next update) */ +void sim_bubble_stage(stage_id_t stage) +{ + switch (stage) + { + case IF_STAGE : pc_state->op = P_BUBBLE; break; + case ID_STAGE : if_id_state->op = P_BUBBLE; break; + case EX_STAGE : id_ex_state->op = P_BUBBLE; break; + case MEM_STAGE: ex_mem_state->op = P_BUBBLE; break; + case WB_STAGE : mem_wb_state->op = P_BUBBLE; break; + } +} + +/* stall stage (has effect at next update) */ +void sim_stall_stage(stage_id_t stage) { + switch (stage) + { + case IF_STAGE : pc_state->op = P_STALL; break; + case ID_STAGE : if_id_state->op = P_STALL; break; + case EX_STAGE : id_ex_state->op = P_STALL; break; + case MEM_STAGE: ex_mem_state->op = P_STALL; break; + case WB_STAGE : mem_wb_state->op = P_STALL; break; + } +} + + +static int initialized = 0; + +void sim_init() +{ + /* Create memory and register files */ + initialized = 1; + mem = init_mem(MEM_SIZE); + reg = init_reg(); + + /* create 5 pipe registers */ + pc_state = new_pipe(sizeof(pc_ele), (void *) &bubble_pc); + if_id_state = new_pipe(sizeof(if_id_ele), (void *) &bubble_if_id); + id_ex_state = new_pipe(sizeof(id_ex_ele), (void *) &bubble_id_ex); + ex_mem_state = new_pipe(sizeof(ex_mem_ele), (void *) &bubble_ex_mem); + mem_wb_state = new_pipe(sizeof(mem_wb_ele), (void *) &bubble_mem_wb); + + /* connect them to the pipeline stages */ + pc_next = pc_state->next; + pc_curr = pc_state->current; + + if_id_next = if_id_state->next; + if_id_curr = if_id_state->current; + + id_ex_next = id_ex_state->next; + id_ex_curr = id_ex_state->current; + + ex_mem_next = ex_mem_state->next; + ex_mem_curr = ex_mem_state->current; + + mem_wb_next = mem_wb_state->next; + mem_wb_curr = mem_wb_state->current; + + sim_reset(); + clear_mem(mem); +} + +void sim_reset() +{ + if (!initialized) + sim_init(); + clear_pipes(); + clear_mem(reg); + minAddr = 0; + memCnt = 0; + starting_up = 1; + cycles = instructions = 0; + cc = DEFAULT_CC; + status = STAT_AOK; + +#ifdef HAS_GUI + if (gui_mode) { + signal_register_clear(); + create_memory_display(); + } +#endif + + amux = bmux = MUX_NONE; + cc = cc_in = DEFAULT_CC; + wb_destE = REG_NONE; + wb_valE = 0; + wb_destM = REG_NONE; + wb_valM = 0; + mem_addr = 0; + mem_data = 0; + mem_write = FALSE; + sim_report(); +} + +/* Update state elements */ +/* May need to disable updating of memory & condition codes */ +static void update_state(bool_t update_mem, bool_t update_cc) +{ + /* Writeback(s): + If either register is REG_NONE, write will have no effect . + Order of two writes determines semantics of + popl %rsp. According to ISA, %rsp will get popped value + */ + + if (wb_destE != REG_NONE) { + sim_log("\tWriteback: Wrote 0x%llx to register %s\n", + wb_valE, reg_name(wb_destE)); + set_reg_val(reg, wb_destE, wb_valE); + } + if (wb_destM != REG_NONE) { + sim_log("\tWriteback: Wrote 0x%llx to register %s\n", + wb_valM, reg_name(wb_destM)); + set_reg_val(reg, wb_destM, wb_valM); + } + + /* Memory write */ + if (mem_write && !update_mem) { + sim_log("\tDisabled write of 0x%llx to address 0x%llx\n", mem_data, mem_addr); + } + if (update_mem && mem_write) { + if (!set_word_val(mem, mem_addr, mem_data)) { + sim_log("\tCouldn't write to address 0x%llx\n", mem_addr); + } else { + sim_log("\tWrote 0x%llx to address 0x%llx\n", mem_data, mem_addr); + +#ifdef HAS_GUI + if (gui_mode) { + if (mem_addr % 8 != 0) { + /* Just did a misaligned write. + Need to display both words */ + word_t align_addr = mem_addr & ~0x3; + word_t val; + get_word_val(mem, align_addr, &val); + set_memory(align_addr, val); + align_addr+=8; + get_word_val(mem, align_addr, &val); + set_memory(align_addr, val); + } else { + set_memory(mem_addr, mem_data); + } + } +#endif + + } + } + if (update_cc) + cc = cc_in; +} + +/* Text representation of status */ +void tty_report(word_t cyc) { + sim_log("\nCycle %lld. CC=%s, Stat=%s\n", cyc, cc_name(cc), stat_name(status)); + + sim_log("F: predPC = 0x%llx\n", pc_curr->pc); + + sim_log("D: instr = %s, rA = %s, rB = %s, valC = 0x%llx, valP = 0x%llx, Stat = %s\n", + iname(HPACK(if_id_curr->icode, if_id_curr->ifun)), + reg_name(if_id_curr->ra), reg_name(if_id_curr->rb), + if_id_curr->valc, if_id_curr->valp, + stat_name(if_id_curr->status)); + + sim_log("E: instr = %s, valC = 0x%llx, valA = 0x%llx, valB = 0x%llx\n srcA = %s, srcB = %s, dstE = %s, dstM = %s, Stat = %s\n", + iname(HPACK(id_ex_curr->icode, id_ex_curr->ifun)), + id_ex_curr->valc, id_ex_curr->vala, id_ex_curr->valb, + reg_name(id_ex_curr->srca), reg_name(id_ex_curr->srcb), + reg_name(id_ex_curr->deste), reg_name(id_ex_curr->destm), + stat_name(id_ex_curr->status)); + + sim_log("M: instr = %s, Cnd = %d, valE = 0x%llx, valA = 0x%llx\n dstE = %s, dstM = %s, Stat = %s\n", + iname(HPACK(ex_mem_curr->icode, ex_mem_curr->ifun)), + ex_mem_curr->takebranch, + ex_mem_curr->vale, ex_mem_curr->vala, + reg_name(ex_mem_curr->deste), reg_name(ex_mem_curr->destm), + stat_name(ex_mem_curr->status)); + + sim_log("W: instr = %s, valE = 0x%llx, valM = 0x%llx, dstE = %s, dstM = %s, Stat = %s\n", + iname(HPACK(mem_wb_curr->icode, mem_wb_curr->ifun)), + mem_wb_curr->vale, mem_wb_curr->valm, + reg_name(mem_wb_curr->deste), reg_name(mem_wb_curr->destm), + stat_name(mem_wb_curr->status)); +} + +/* Run pipeline for one cycle */ +/* Return status of processor */ +/* Max_instr indicates maximum number of instructions that + want to complete during this simulation run. */ +static byte_t sim_step_pipe(word_t max_instr, word_t ccount) +{ + byte_t wb_status = mem_wb_curr->status; + byte_t mem_status = mem_wb_next->status; + /* How many instructions are ahead of one in wb / ex? */ + int ahead_mem = (wb_status != STAT_BUB); + int ahead_ex = ahead_mem + (mem_status != STAT_BUB); + bool_t update_mem = ahead_mem < max_instr; + bool_t update_cc = ahead_ex < max_instr; + + /* Update program-visible state */ + update_state(update_mem, update_cc); + /* Update pipe registers */ + update_pipes(); + tty_report(ccount); + if (pc_state->op == P_ERROR) + pc_curr->status = STAT_PIP; + if (if_id_state->op == P_ERROR) + if_id_curr->status = STAT_PIP; + if (id_ex_state->op == P_ERROR) + id_ex_curr->status = STAT_PIP; + if (ex_mem_state->op == P_ERROR) + ex_mem_curr->status = STAT_PIP; + if (mem_wb_state->op == P_ERROR) + mem_wb_curr->status = STAT_PIP; + + /* Need to do decode after execute & memory stages, + and memory stage before execute, in order to propagate + forwarding values properly */ + do_if_stage(); + do_mem_stage(); + do_ex_stage(); + do_id_wb_stages(); + + do_stall_check(); +#if 0 + /* This doesn't seem necessary */ + if (id_ex_curr->status != STAT_AOK + && id_ex_curr->status != STAT_BUB) { + if_id_state->op = P_BUBBLE; + id_ex_state->op = P_BUBBLE; + } +#endif + + /* Performance monitoring */ + if (mem_wb_curr->status != STAT_BUB && mem_wb_curr->icode != I_POP2) { + starting_up = 0; + instructions++; + cycles++; + } else { + if (!starting_up) + cycles++; + } + + sim_report(); + return status; +} + +/* + Run pipeline until one of following occurs: + - An error status is encountered in WB. + - max_instr instructions have completed through WB + - max_cycle cycles have been simulated + + Return number of instructions executed. + if statusp nonnull, then will be set to status of final instruction + if ccp nonnull, then will be set to condition codes of final instruction +*/ +word_t sim_run_pipe(word_t max_instr, word_t max_cycle, byte_t *statusp, cc_t *ccp) +{ + word_t icount = 0; + word_t ccount = 0; + byte_t run_status = STAT_AOK; + while (icount < max_instr && ccount < max_cycle) { + run_status = sim_step_pipe(max_instr-icount, ccount); + if (run_status != STAT_BUB) + icount++; + if (run_status != STAT_AOK && run_status != STAT_BUB) + break; + ccount++; + } + if (statusp) + *statusp = run_status; + if (ccp) + *ccp = cc; + return icount; +} + +/* If dumpfile set nonNULL, lots of status info printed out */ +void sim_set_dumpfile(FILE *df) +{ + dumpfile = df; +} + +/* + * sim_log dumps a formatted string to the dumpfile, if it exists + * accepts variable argument list + */ +void sim_log( const char *format, ... ) { + if (dumpfile) { + va_list arg; + va_start( arg, format ); + vfprintf( dumpfile, format, arg ); + va_end( arg ); + } +} + + +/************************************************************* + * Part 3: This part contains support for the GUI simulator + *************************************************************/ + +#ifdef HAS_GUI + +/********************** + * Begin Part 3 globals + **********************/ + +/* Hack for SunOS */ +extern int matherr(); +int *tclDummyMathPtr = (int *) matherr; + +static char tcl_msg[256]; + +/* Keep track of the TCL Interpreter */ +static Tcl_Interp *sim_interp = NULL; + +static mem_t post_load_mem; + +/********************** + * End Part 3 globals + **********************/ + + +/****************************************************************************** + * function declarations + ******************************************************************************/ + +int simResetCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); + +int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); + +int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); + +int simRunCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); + +int simModeCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); + +void addAppCommands(Tcl_Interp *interp); + + +/****************************************************************************** + * tcl command definitions + ******************************************************************************/ + +/* Implement command versions of the simulation functions */ +int simResetCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + sim_interp = interp; + if (argc != 1) { + interp->result = "No arguments allowed"; + return TCL_ERROR; + } + sim_reset(); + if (post_load_mem) { + free_mem(mem); + mem = copy_mem(post_load_mem); + } + interp->result = stat_name(STAT_AOK); + return TCL_OK; +} + +int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + FILE *code_file; + word_t code_count; + sim_interp = interp; + if (argc != 2) { + interp->result = "One argument required"; + return TCL_ERROR; + } + code_file = fopen(argv[1], "r"); + if (!code_file) { + sprintf(tcl_msg, "Couldn't open code file '%s'", argv[1]); + interp->result = tcl_msg; + return TCL_ERROR; + } + sim_reset(); + code_count = load_mem(mem, code_file, 0); + post_load_mem = copy_mem(mem); + sprintf(tcl_msg, "%lld", code_count); + interp->result = tcl_msg; + fclose(code_file); + return TCL_OK; +} + +int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + FILE *data_file; + word_t word_count = 0; + interp->result = "Not implemented"; + return TCL_ERROR; + + + sim_interp = interp; + if (argc != 2) { + interp->result = "One argument required"; + return TCL_ERROR; + } + data_file = fopen(argv[1], "r"); + if (!data_file) { + sprintf(tcl_msg, "Couldn't open data file '%s'", argv[1]); + interp->result = tcl_msg; + return TCL_ERROR; + } + sprintf(tcl_msg, "%lld", word_count); + interp->result = tcl_msg; + fclose(data_file); + return TCL_OK; +} + + +int simRunCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + word_t cycle_limit = 1; + byte_t status; + cc_t cc; + sim_interp = interp; + if (argc > 2) { + interp->result = "At most one argument allowed"; + return TCL_ERROR; + } + if (argc >= 2 && + (sscanf(argv[1], "%lld", &cycle_limit) != 1 || + cycle_limit < 0)) { + sprintf(tcl_msg, "Cannot run for '%s' cycles!", argv[1]); + interp->result = tcl_msg; + return TCL_ERROR; + } + sim_run_pipe(cycle_limit + 5, cycle_limit, &status, &cc); + interp->result = stat_name(status); + return TCL_OK; +} + +int simModeCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + sim_interp = interp; + if (argc != 2) { + interp->result = "One argument required"; + return TCL_ERROR; + } + interp->result = argv[1]; + if (strcmp(argv[1], "wedged") == 0) + sim_mode = S_WEDGED; + else if (strcmp(argv[1], "stall") == 0) + sim_mode = S_STALL; + else if (strcmp(argv[1], "forward") == 0) + sim_mode = S_FORWARD; + else { + sprintf(tcl_msg, "Unknown mode '%s'", argv[1]); + interp->result = tcl_msg; + return TCL_ERROR; + } + return TCL_OK; +} + + +/****************************************************************************** + * registering the commands with tcl + ******************************************************************************/ + +void addAppCommands(Tcl_Interp *interp) +{ + sim_interp = interp; + Tcl_CreateCommand(interp, "simReset", (Tcl_CmdProc *) simResetCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "simCode", (Tcl_CmdProc *) simLoadCodeCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "simData", (Tcl_CmdProc *) simLoadDataCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "simRun", (Tcl_CmdProc *) simRunCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "setSimMode", (Tcl_CmdProc *) simModeCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); +} + +/****************************************************************************** + * tcl functionality called from within C + ******************************************************************************/ + +/* Provide mechanism for simulator to update register display */ +void signal_register_update(reg_id_t r, word_t val) { + int code; + sprintf(tcl_msg, "setReg %d %lld 1", (int) r, (word_t) val); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to signal register set\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Provide mechanism for simulator to generate memory display */ +void create_memory_display() { + int code; + sprintf(tcl_msg, "createMem %lld %lld", minAddr, memCnt); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Command '%s' failed\n", tcl_msg); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } else { + word_t i; + for (i = 0; i < memCnt && code == TCL_OK; i+=8) { + word_t addr = minAddr+i; + word_t val; + if (!get_word_val(mem, addr, &val)) { + fprintf(stderr, "Out of bounds memory display\n"); + return; + } + sprintf(tcl_msg, "setMem %lld %lld", addr, val); + code = Tcl_Eval(sim_interp, tcl_msg); + } + if (code != TCL_OK) { + fprintf(stderr, "Couldn't set memory value\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } + } +} + +/* Provide mechanism for simulator to update memory value */ +void set_memory(word_t addr, word_t val) { + int code; + word_t nminAddr = minAddr; + word_t nmemCnt = memCnt; + + /* First see if we need to expand memory range */ + if (memCnt == 0) { + nminAddr = addr; + nmemCnt = 8; + } else if (addr < minAddr) { + nminAddr = addr; + nmemCnt = minAddr + memCnt - addr; + } else if (addr >= minAddr+memCnt) { + nmemCnt = addr-minAddr+8; + } + /* Now make sure nminAddr & nmemCnt are multiples of 16 */ + nmemCnt = ((nminAddr & 0xF) + nmemCnt + 0xF) & ~0xF; + nminAddr = nminAddr & ~0xF; + + if (nminAddr != minAddr || nmemCnt != memCnt) { + minAddr = nminAddr; + memCnt = nmemCnt; + create_memory_display(); + } else { + sprintf(tcl_msg, "setMem %lld %lld", addr, val); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Couldn't set memory value 0x%llx to 0x%llx\n", + addr, val); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } + } +} + +/* Provide mechanism for simulator to update condition code display */ +void show_cc(cc_t cc) +{ + int code; + sprintf(tcl_msg, "setCC %d %d %d", + GET_ZF(cc), GET_SF(cc), GET_OF(cc)); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to display condition codes\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Provide mechanism for simulator to update status display */ +void show_stat(stat_t stat) +{ + int code; + sprintf(tcl_msg, "showStat %s", stat_name(stat)); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to display status\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + + + +/* Provide mechanism for simulator to update performance information */ +void show_cpi() { + int code; + double cpi = instructions > 0 ? (double) cycles/instructions : 1.0; + sprintf(tcl_msg, "showCPI %lld %lld %.2f", + cycles, instructions, (double) cpi); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to display CPI\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +char *rname[] = {"none", "ea", "eb", "me", "wm", "we"}; + +/* provide mechanism for simulator to specify source registers */ +void signal_sources() { + int code; + sprintf(tcl_msg, "showSources %s %s", + rname[amux], rname[bmux]); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to signal forwarding sources\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Provide mechanism for simulator to clear register display */ +void signal_register_clear() { + int code; + code = Tcl_Eval(sim_interp, "clearReg"); + if (code != TCL_OK) { + fprintf(stderr, "Failed to signal register clear\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Provide mechanism for simulator to report instructions as they are + read in +*/ + +void report_line(word_t line_no, word_t addr, char *hex, char *text) { + int code; + sprintf(tcl_msg, "addCodeLine %lld %lld {%s} {%s}", line_no, addr, hex, text); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to report code line 0x%llx\n", addr); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + + +/* Provide mechanism for simulator to report which instructions are in + which stages */ +void report_pc(unsigned fpc, unsigned char fpcv, + unsigned dpc, unsigned char dpcv, + unsigned epc, unsigned char epcv, + unsigned mpc, unsigned char mpcv, + unsigned wpc, unsigned char wpcv) +{ + int status; + char addr[10]; + char code[12]; + Tcl_DString cmd; + Tcl_DStringInit(&cmd); + Tcl_DStringAppend(&cmd, "simLabel ", -1); + Tcl_DStringStartSublist(&cmd); + if (fpcv) { + sprintf(addr, "%u", fpc); + Tcl_DStringAppendElement(&cmd, addr); + } + if (dpcv) { + sprintf(addr, "%u", dpc); + Tcl_DStringAppendElement(&cmd, addr); + } + if (epcv) { + sprintf(addr, "%u", epc); + Tcl_DStringAppendElement(&cmd, addr); + } + if (mpcv) { + sprintf(addr, "%u", mpc); + Tcl_DStringAppendElement(&cmd, addr); + } + if (wpcv) { + sprintf(addr, "%u", wpc); + Tcl_DStringAppendElement(&cmd, addr); + } + Tcl_DStringEndSublist(&cmd); + Tcl_DStringStartSublist(&cmd); + sprintf(code, "%s %s %s %s %s", + fpcv ? "F" : "", + dpcv ? "D" : "", + epcv ? "E" : "", + mpcv ? "M" : "", + wpcv ? "W" : ""); + Tcl_DStringAppend(&cmd, code, -1); + Tcl_DStringEndSublist(&cmd); + /* Debug + fprintf(stderr, "Code '%s'\n", Tcl_DStringValue(&cmd)); + */ + status = Tcl_Eval(sim_interp, Tcl_DStringValue(&cmd)); + if (status != TCL_OK) { + fprintf(stderr, "Failed to report pipe code '%s'\n", code); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Report single line of pipeline state */ +void report_state(char *id, word_t current, char *txt) +{ + int status; + sprintf(tcl_msg, "updateStage %s %lld {%s}", id, current,txt); + status = Tcl_Eval(sim_interp, tcl_msg); + if (status != TCL_OK) { + fprintf(stderr, "Failed to report pipe status\n"); + fprintf(stderr, "\tStage %s.%s, status '%s'\n", + id, current ? "current" : "next", txt); + fprintf(stderr, "\tError Message was '%s'\n", sim_interp->result); + } +} + + +/* + * Tcl_AppInit - Called by TCL to perform application-specific initialization. + */ +int Tcl_AppInit(Tcl_Interp *interp) +{ + /* Tell TCL about the name of the simulator so it can */ + /* use it as the title of the main window */ + Tcl_SetVar(interp, "simname", simname, TCL_GLOBAL_ONLY); + + if (Tcl_Init(interp) == TCL_ERROR) + return TCL_ERROR; + if (Tk_Init(interp) == TCL_ERROR) + return TCL_ERROR; + Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); + + /* Call procedure to add new commands */ + addAppCommands(interp); + + /* + * Specify a user-specific startup file to invoke if the application + * is run interactively. Typically the startup file is "~/.apprc" + * where "app" is the name of the application. If this line is deleted + * then no user-specific startup file will be run under any conditions. + */ + Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY); + return TCL_OK; + +} + +#endif /* HAS_GUI */ + + +/************************************************************** + * Part 4: Code for implementing pipelined processor simulators + *************************************************************/ + +/****************************************************************************** + * defines + ******************************************************************************/ + +#define MAX_STAGE 10 + +/****************************************************************************** + * static variables + ******************************************************************************/ + +static pipe_ptr pipes[MAX_STAGE]; +static int pipe_count = 0; + +/****************************************************************************** + * function definitions + ******************************************************************************/ + +/* Create new pipe with count bytes of state */ +/* bubble_val indicates state corresponding to pipeline bubble */ +pipe_ptr new_pipe(int count, void *bubble_val) +{ + pipe_ptr result = (pipe_ptr) malloc(sizeof(pipe_ele)); + result->current = malloc(count); + result->next = malloc(count); + memcpy(result->current, bubble_val, count); + memcpy(result->next, bubble_val, count); + result->count = count; + result->op = P_LOAD; + result->bubble_val = bubble_val; + pipes[pipe_count++] = result; + return result; +} + +/* Update all pipes */ +void update_pipes() +{ + int s; + for (s = 0; s < pipe_count; s++) { + pipe_ptr p = pipes[s]; + switch (p->op) + { + case P_BUBBLE: + /* insert a bubble into the next stage */ + memcpy(p->current, p->bubble_val, p->count); + break; + + case P_LOAD: + /* copy calculated state from previous stage */ + memcpy(p->current, p->next, p->count); + break; + case P_ERROR: + /* Like a bubble, but insert error condition */ + memcpy(p->current, p->bubble_val, p->count); + break; + case P_STALL: + default: + /* do nothing: next stage gets same instr again */ + ; + } + if (p->op != P_ERROR) + p->op = P_LOAD; + } +} + +/* Set all pipes to bubble values */ +void clear_pipes() +{ + int s; + for (s = 0; s < pipe_count; s++) { + pipe_ptr p = pipes[s]; + memcpy(p->current, p->bubble_val, p->count); + memcpy(p->next, p->bubble_val, p->count); + p->op = P_LOAD; + } +} + +/******************** Utility Code *************************/ + +/* Representations of digits */ +static char digits[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +/* Print hex/oct/binary format with leading zeros */ +/* bpd denotes bits per digit Should be in range 1-4, + pbw denotes bits per word.*/ +void wprint(uword_t x, int bpd, int bpw, FILE *fp) +{ + int digit; + uword_t mask = ((uword_t) 1 << bpd) - 1; + for (digit = (bpw-1)/bpd; digit >= 0; digit--) { + uword_t val = (x >> (digit * bpd)) & mask; + putc(digits[val], fp); + } +} + +/* Create string in hex/oct/binary format with leading zeros */ +/* bpd denotes bits per digit Should be in range 1-4, + pbw denotes bits per word.*/ +void wstring(uword_t x, int bpd, int bpw, char *str) +{ + int digit; + uword_t mask = ((uword_t) 1 << bpd) - 1; + for (digit = (bpw-1)/bpd; digit >= 0; digit--) { + uword_t val = (x >> (digit * bpd)) & mask; + *str++ = digits[val]; + } + *str = '\0'; +} + + +/******************************** + * Part 5: Stage implementations + *********************************/ + +/*************** Bubbled version of stages *************/ + +pc_ele bubble_pc = {0,STAT_AOK}; +if_id_ele bubble_if_id = { I_NOP, 0, REG_NONE,REG_NONE, + 0, 0, STAT_BUB, 0}; +id_ex_ele bubble_id_ex = { I_NOP, 0, 0, 0, 0, + REG_NONE, REG_NONE, REG_NONE, REG_NONE, + STAT_BUB, 0}; + +ex_mem_ele bubble_ex_mem = { I_NOP, 0, FALSE, 0, 0, + REG_NONE, REG_NONE, STAT_BUB, 0}; + +mem_wb_ele bubble_mem_wb = { I_NOP, 0, 0, 0, REG_NONE, REG_NONE, + STAT_BUB, 0}; + +/*************** Stage Implementations *****************/ + +word_t gen_f_pc(); +word_t gen_need_regids(); +word_t gen_need_valC(); +word_t gen_instr_valid(); +word_t gen_f_predPC(); +word_t gen_f_icode(); +word_t gen_f_ifun(); +word_t gen_f_stat(); +word_t gen_instr_valid(); + +void do_if_stage() +{ + byte_t instr = HPACK(I_NOP, F_NONE); + byte_t regids = HPACK(REG_NONE, REG_NONE); + word_t valc = 0; + word_t valp = f_pc = gen_f_pc(); + + /* Ready to fetch instruction. Speculatively fetch register byte + and immediate word + */ + imem_error = !get_byte_val(mem, valp, &instr); + imem_icode = HI4(instr); + imem_ifun = LO4(instr); + if (!imem_error) { + byte_t junk; + /* Make sure can read maximum length instruction */ + imem_error = !get_byte_val(mem, valp+5, &junk); + } + if_id_next->icode = gen_f_icode(); + if_id_next->ifun = gen_f_ifun(); + if (!imem_error) { + sim_log("\tFetch: f_pc = 0x%llx, imem_instr = %s, f_instr = %s\n", + f_pc, iname(instr), + iname(HPACK(if_id_next->icode, if_id_next->ifun))); + } + + instr_valid = gen_instr_valid(); + if (!instr_valid) + sim_log("\tFetch: Instruction code 0x%llx invalid\n", instr); + if_id_next->status = gen_f_stat(); + + valp++; + if (gen_need_regids()) { + get_byte_val(mem, valp, ®ids); + valp ++; + } + if_id_next->ra = HI4(regids); + if_id_next->rb = LO4(regids); + if (gen_need_valC()) { + get_word_val(mem, valp, &valc); + valp+= 8; + } + if_id_next->valp = valp; + if_id_next->valc = valc; + + pc_next->pc = gen_f_predPC(); + + pc_next->status = (if_id_next->status == STAT_AOK) ? STAT_AOK : STAT_BUB; + + if_id_next->stage_pc = f_pc; +} + +word_t gen_d_srcA(); +word_t gen_d_srcB(); +word_t gen_d_dstE(); +word_t gen_d_dstM(); +word_t gen_d_valA(); +word_t gen_d_valB(); +word_t gen_w_dstE(); +word_t gen_w_valE(); +word_t gen_w_dstM(); +word_t gen_w_valM(); +word_t gen_Stat(); + +/* Implements both ID and WB */ +void do_id_wb_stages() +{ + /* Set up write backs. Don't occur until end of cycle */ + wb_destE = gen_w_dstE(); + wb_valE = gen_w_valE(); + wb_destM = gen_w_dstM(); + wb_valM = gen_w_valM(); + + /* Update processor status */ + status = gen_Stat(); + + id_ex_next->srca = gen_d_srcA(); + id_ex_next->srcb = gen_d_srcB(); + id_ex_next->deste = gen_d_dstE(); + id_ex_next->destm = gen_d_dstM(); + + /* Read the registers */ + d_regvala = get_reg_val(reg, id_ex_next->srca); + d_regvalb = get_reg_val(reg, id_ex_next->srcb); + + /* Do forwarding and valA selection */ + id_ex_next->vala = gen_d_valA(); + id_ex_next->valb = gen_d_valB(); + + id_ex_next->icode = if_id_curr->icode; + id_ex_next->ifun = if_id_curr->ifun; + id_ex_next->valc = if_id_curr->valc; + id_ex_next->stage_pc = if_id_curr->stage_pc; + id_ex_next->status = if_id_curr->status; +} + +word_t gen_alufun(); +word_t gen_set_cc(); +word_t gen_Bch(); +word_t gen_aluA(); +word_t gen_aluB(); +word_t gen_e_valA(); +word_t gen_e_dstE(); + +void do_ex_stage() +{ + alu_t alufun = gen_alufun(); + bool_t setcc = gen_set_cc(); + word_t alua, alub; + + alua = gen_aluA(); + alub = gen_aluB(); + + e_bcond = cond_holds(cc, id_ex_curr->ifun); + + ex_mem_next->takebranch = e_bcond; + + if (id_ex_curr->icode == I_JMP) + sim_log("\tExecute: instr = %s, cc = %s, branch %staken\n", + iname(HPACK(id_ex_curr->icode, id_ex_curr->ifun)), + cc_name(cc), + ex_mem_next->takebranch ? "" : "not "); + + /* Perform the ALU operation */ + word_t aluout = compute_alu(alufun, alua, alub); + ex_mem_next->vale = aluout; + sim_log("\tExecute: ALU: %c 0x%llx 0x%llx --> 0x%llx\n", + op_name(alufun), alua, alub, aluout); + + if (setcc) { + cc_in = compute_cc(alufun, alua, alub); + sim_log("\tExecute: New cc = %s\n", cc_name(cc_in)); + } + + ex_mem_next->icode = id_ex_curr->icode; + ex_mem_next->ifun = id_ex_curr->ifun; + ex_mem_next->vala = gen_e_valA(); + ex_mem_next->deste = gen_e_dstE(); + ex_mem_next->destm = id_ex_curr->destm; + ex_mem_next->srca = id_ex_curr->srca; + ex_mem_next->status = id_ex_curr->status; + ex_mem_next->stage_pc = id_ex_curr->stage_pc; +} + +/* Functions defined using HCL */ +word_t gen_mem_addr(); +word_t gen_mem_read(); +word_t gen_mem_write(); +word_t gen_m_stat(); + +void do_mem_stage() +{ + bool_t read = gen_mem_read(); + + word_t valm = 0; + + mem_addr = gen_mem_addr(); + mem_data = ex_mem_curr->vala; + mem_write = gen_mem_write(); + dmem_error = FALSE; + + if (read) { + dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm); + if (!dmem_error) + sim_log("\tMemory: Read 0x%llx from 0x%llx\n", + valm, mem_addr); + } + if (mem_write) { + word_t sink; + /* Do a read of address just to check validity */ + dmem_error = dmem_error || !get_word_val(mem, mem_addr, &sink); + if (dmem_error) + sim_log("\tMemory: Invalid address 0x%llx\n", + mem_addr); + } + mem_wb_next->icode = ex_mem_curr->icode; + mem_wb_next->ifun = ex_mem_curr->ifun; + mem_wb_next->vale = ex_mem_curr->vale; + mem_wb_next->valm = valm; + mem_wb_next->deste = ex_mem_curr->deste; + mem_wb_next->destm = ex_mem_curr->destm; + mem_wb_next->status = gen_m_stat(); + mem_wb_next->stage_pc = ex_mem_curr->stage_pc; +} + +/* Set stalling conditions for different stages */ + +word_t gen_F_stall(), gen_F_bubble(); +word_t gen_D_stall(), gen_D_bubble(); +word_t gen_E_stall(), gen_E_bubble(); +word_t gen_M_stall(), gen_M_bubble(); +word_t gen_W_stall(), gen_W_bubble(); + +p_stat_t pipe_cntl(char *name, word_t stall, word_t bubble) +{ + if (stall) { + if (bubble) { + sim_log("%s: Conflicting control signals for pipe register\n", + name); + return P_ERROR; + } else + return P_STALL; + } else { + return bubble ? P_BUBBLE : P_LOAD; + } +} + +void do_stall_check() +{ + pc_state->op = pipe_cntl("PC", gen_F_stall(), gen_F_bubble()); + if_id_state->op = pipe_cntl("ID", gen_D_stall(), gen_D_bubble()); + id_ex_state->op = pipe_cntl("EX", gen_E_stall(), gen_E_bubble()); + ex_mem_state->op = pipe_cntl("MEM", gen_M_stall(), gen_M_bubble()); + mem_wb_state->op = pipe_cntl("WB", gen_W_stall(), gen_W_bubble()); +} + + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/sim.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/sim.h new file mode 100644 index 00000000..b176318c --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/sim.h @@ -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 + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/stages.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/stages.h new file mode 100644 index 00000000..a86db9a3 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/pipe/stages.h @@ -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(); + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/Makefile b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/Makefile new file mode 100644 index 00000000..bc356e2b --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/Makefile @@ -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 + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/README b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/README new file mode 100644 index 00000000..7ea96255 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/README @@ -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= + +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. diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/ctest.pl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/ctest.pl new file mode 100755 index 00000000..1788aeee --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/ctest.pl @@ -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 <$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(); diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/htest.pl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/htest.pl new file mode 100755 index 00000000..210f9403 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/htest.pl @@ -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 <$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(); diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/jtest.pl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/jtest.pl new file mode 100755 index 00000000..5d60b5f4 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/ptest/jtest.pl @@ -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 <$tname.ys") || die "Can't write to $tname.ys\n"; + print YFILE <$tname.ys") || die "Can't write to $tname.ys\n"; + print YFILE <$tname.ys") || die "Can't write to $tname.ys\n"; + print YFILE <$tname.ys") || die "Can't write to $tname.ys\n"; + print YFILE <$tname.ys") || die "Can't write to $tname.ys\n"; + print YFILE <] [-P] [-p ]\n"; + print STDERR " -h print Help message\n"; + print STDERR " -i test iaddq instruction\n"; + print STDERR " -s Specify simulator\n"; + print STDERR " -d Specify directory for counterexamples\n"; + print STDERR " -P Generate performance data\n"; + print STDERR " -p Check using performance file \n"; + print STDERR " -V test Verilog implementation\n"; + print STDERR " -m 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; + + + + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/Makefile b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/Makefile new file mode 100644 index 00000000..ba7aada4 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/Makefile @@ -0,0 +1,65 @@ +# Modify this line to indicate the default version + +VERSION=std + +# Comment this out if you don't have Tcl/Tk on your system + +GUIMODE= + +# 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= + +# 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= + +# Modify these two lines to choose your compiler and compile time +# flags. + +CC=gcc +CFLAGS=-Wall -O1 -g -fcommon -Wno-error + +################################################## +# 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).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.c + $(CC) $(CFLAGS) $(INC) -o ssim+ \ + seq+-std.c ssim.c $(MISCDIR)/isa.c $(LIBS) + +# These are implicit rules for assembling .yo files from .ys files. +.SUFFIXES: .ys .yo +.ys.yo: + $(YAS) $*.ys + + +clean: + rm -f ssim ssim+ seq*-*.c *.o *~ *.exe *.yo *.ys + + + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/README b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/README new file mode 100644 index 00000000..2a3157fd --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/README @@ -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) + + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq+-std.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq+-std.hcl new file mode 100644 index 00000000..a0458321 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq+-std.hcl @@ -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 ' +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 */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq+.tcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq+.tcl new file mode 100644 index 00000000..73b0627d --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq+.tcl @@ -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 " "%r9 " "%r10" "%r11" "%r12" "%r13" "%r14" ""] + +# Create rows of register labels and displays +for {set j 0} {$j < 3} {incr j 1} { + frame .r.labels$j + pack .r.labels$j -side top -in .r + + for {set c 0} {$c < 5} {incr c 1} { + set i [expr $j * 5 + $c] + label .r.lab$i -width 16 -font $dpyFont -text [lindex $regnames $i] + pack .r.lab$i -in .r.labels$j -side left + } + + # Create Row of Register Entries + frame .r.row$j + pack .r.row$j -side top -in .r + + # Create 5 registers + for {set c 0} {$c < 5} {incr c 1} { + set i [expr $j * 5 + $c] + if {$i == 15} { + label .r.reg$i -width 16 -font $dpyFont -text "" + } else { + label .r.reg$i -width 16 -font $dpyFont -relief ridge \ + -bg $normalBg + } + pack .r.reg$i -in .r.row$j -side left + } + +} + +############################################################################## +# Main Control Panel # +############################################################################## +# +# Set the simulator name (defined in simname in ssim.c) +# as the title of the main window +# +wm title . $simname +#wm title . "Y86-64 Simulator" + +# Control Panel for simulator +set cntlBW 11 +frame .cntl +pack .cntl +button .cntl.quit -width $cntlBW -text Quit -command exit +button .cntl.run -width $cntlBW -text Go -command simGo +button .cntl.stop -width $cntlBW -text Stop -command simStop +button .cntl.step -width $cntlBW -text Step -command simStep +button .cntl.reset -width $cntlBW -text Reset -command simResetAll +pack .cntl.quit .cntl.run .cntl.stop .cntl.step .cntl.reset -in .cntl -side left +# Simulation speed control +scale .spd -label {Simulator Speed (10*log Hz)} -from -10 -to 30 -length 10c \ + -orient horizontal -command setSpeed +pack .spd + +# Simulation mode +set simMode forward + +# frame .md +# pack .md +# radiobutton .md.wedged -text Wedged -variable simMode \ +# -value wedged -width 10 -command {setSimMode wedged} +# radiobutton .md.stall -text Stall -variable simMode \ +# -value stall -width 10 -command {setSimMode stall} +# radiobutton .md.forward -text Forward -variable simMode \ +# -value forward -width 10 -command {setSimMode forward} +# pack .md.wedged .md.stall .md.forward -in .md -side left + +# simDelay defines #milliseconds for each cycle of simulator +# Initial value is 1000ms +set simDelay 1000 +# Set delay based on rate expressed in log(Hz) +proc setSpeed {rate} { + global simDelay + set simDelay [expr round(1000 / pow(10,$rate/10.0))] +} + +# Global variables controlling simulator execution +# Should simulator be running now? +set simGoOK 0 + +proc simStop {} { + global simGoOK + set simGoOK 0 +} + +proc simStep {} { + global simStat + set simStat [simRun 1] +} + +proc simGo {} { + global simGoOK simDelay simStat + set simGoOK 1 + # Disable the Go and Step buttons + # Enable the Stop button + while {$simGoOK} { + # run the simulator 1 cycle + after $simDelay + set simStat [simRun 1] + if {$simStat != "AOK" && $simStat != "BUB"} {set simGoOK 0} + update + } + # Disable the Stop button + # Enable the Go and Step buttons +} + +############################################################################## +# Processor State display # +############################################################################## + +# Overall width of pipe register display +set procWidth 60 +set procHeight 1 +set labWidth 8 + +# Add labeled display to window +proc addDisp {win width name} { + global dpyFont labFont + set lname [string tolower $name] + frame $win.$lname + pack $win.$lname -in $win -side left + label $win.$lname.t -text $name -font $labFont + label $win.$lname.c -width $width -font $dpyFont -bg white -relief ridge + pack $win.$lname.t $win.$lname.c -in $win.$lname -side top + return [list $win.$lname.c] +} + +# Set text in display row +proc setDisp {wins txts} { + for {set i 0} {$i < [llength $wins] && $i < [llength $txts]} {incr i} { + set win [lindex $wins $i] + set txt [lindex $txts $i] + $win config -text $txt + } +} + +frame .p -width $procWidth +pack .p -in . -side bottom +label .p.lab -text "Processor State" -height $sectionHeight -font $bigLabFont +pack .p.lab -in .p -side top +label .p.mem -text "Memory Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.ex -text "Execute Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.id -text "Decode Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.if -text "Fetch Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.pcc -text "PC Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +# Mem +frame .p.m +# Execute +frame .p.e +# Decode +frame .p.d +# Fetch +frame .p.f +# PC +frame .p.pc +# Prev +frame .p.prev +pack .p.m .p.mem .p.e .p.ex .p.d .p.id .p.f .p.if .p.pc .p.pcc .p.prev -in .p -side top -anchor w -expand 1 + +# Take list of lists, and transpose nesting +# Assumes all lists are of same length +proc ltranspose {inlist} { + set result {} + for {set i 0} {$i < [llength [lindex $inlist 0]]} {incr i} { + set nlist {} + for {set j 0} {$j < [llength $inlist]} {incr j} { + set ele [lindex [lindex $inlist $j] $i] + set nlist [concat $nlist [list $ele]] + } + set result [concat $result [list $nlist]] + } + return $result +} + +# Fields in PREV display +# Total size = 57 +set pwins(PREV) [ltranspose \ + [list [addDisp .p.prev 3 pCnd] \ + [addDisp .p.prev 6 pInstr] \ + [addDisp .p.prev 16 pValC] \ + [addDisp .p.prev 16 pValM] \ + [addDisp .p.prev 16 pValP]]] + + +# Fields in PC display +# Total size = 16 +set pwins(PC) [ltranspose [list [addDisp .p.pc 16 PC]]] + +# Fetch display +# Total size = 6+4+4+16+16 = 46 +set pwins(F) [ltranspose \ + [list [addDisp .p.f 6 Instr] \ + [addDisp .p.f 4 rA]\ + [addDisp .p.f 4 rB] \ + [addDisp .p.f 16 valC] \ + [addDisp .p.f 16 valP]]] + +# Decode Display +# Total size = 16+16+4+4+4+4 = 48 +set pwins(D) [ltranspose \ + [list [addDisp .p.d 16 valA] \ + [addDisp .p.d 16 valB] \ + [addDisp .p.d 4 dstE] \ + [addDisp .p.d 4 dstM] \ + [addDisp .p.d 4 srcA] \ + [addDisp .p.d 4 srcB]]] + +# Execute Display +# Total size = 3+16 = 19 +set pwins(E) [ltranspose \ + [list [addDisp .p.e 3 Cnd] \ + [addDisp .p.e 16 valE]]] + +# Memory Display +# Total size = 16 +set pwins(M) [ltranspose \ + [list [addDisp .p.m 16 valM]]] + +# update status line for specified proc register +proc updateStage {name txts} { + set Name [string toupper $name] + global pwins + set wins [lindex $pwins($Name) 0] + setDisp $wins $txts +} + +########################################################################## +# Instruction Display # +########################################################################## + +toplevel .c +wm title .c "Program Code" +frame .c.cntl +pack .c.cntl -in .c -side top -anchor w +label .c.filelab -width 10 -text "File" +entry .c.filename -width 20 -relief sunken -textvariable codeFile \ + -font $dpyFont -bg white +button .c.loadbutton -width $cntlBW -command {loadCode $codeFile} -text Load +pack .c.filelab .c.filename .c.loadbutton -in .c.cntl -side left + +proc clearCode {} { + simLabel {} {} + destroy .c.t + destroy .c.tr +} + +proc createCode {} { + # Create Code Structure + frame .c.t + pack .c.t -in .c -side top -anchor w + frame .c.tr + pack .c.tr -in .c.t -side top -anchor nw +} + +proc loadCode {file} { + # Kill old code window + clearCode + # Create new one + createCode + simCode $file + simResetAll +} + +# Start with initial code window, even though it will be destroyed. +createCode + +# Add a line of code to the display +proc addCodeLine {line addr op text} { + global codeRowCount + # Create new line in display + global codeFont + frame .c.tr.$addr + pack .c.tr.$addr -in .c.tr -side top -anchor w + label .c.tr.$addr.a -width 6 -text [format "0x%x" $addr] -font $codeFont + label .c.tr.$addr.i -width 20 -text $op -font $codeFont + label .c.tr.$addr.s -width 2 -text "" -font $codeFont -bg white + label .c.tr.$addr.t -text $text -font $codeFont + pack .c.tr.$addr.a .c.tr.$addr.i .c.tr.$addr.s \ + .c.tr.$addr.t -in .c.tr.$addr -side left +} + +# Keep track of which instructions have stage labels + +set oldAddr {} + +proc simLabel {addrs labs} { + global oldAddr + set newAddr {} + # Clear away any old labels + foreach a $oldAddr { + .c.tr.$a.s config -text "" + } + for {set i 0} {$i < [llength $addrs]} {incr i} { + set a [lindex $addrs $i] + set t [lindex $labs $i] + if {[winfo exists .c.tr.$a]} { + .c.tr.$a.s config -text $t + set newAddr [concat $newAddr $a] + } + } + set oldAddr $newAddr +} + +proc simResetAll {} { + global simStat + set simStat "AOK" + simReset + simLabel {} {} + clearMem +} + +############################################################################### +# Memory Display # +############################################################################### +toplevel .m +wm title .m "Memory Contents" +frame .m.t +pack .m.t -in .m -side top -anchor w + +label .m.t.lab -width 6 -font $dpyFont -text " " +pack .m.t.lab -in .m.t -side left +for {set i 0} {$i < 16} {incr i 8} { + label .m.t.a$i -width 16 -font $dpyFont -text [format " 0x---%x" [expr $i % 16]] + pack .m.t.a$i -in .m.t -side left +} + + +# Keep track of range of addresses currently displayed +set minAddr 0 +set memCnt 0 +set haveMem 0 + +proc createMem {nminAddr nmemCnt} { + global minAddr memCnt haveMem codeFont dpyFont normalBg + set minAddr $nminAddr + set memCnt $nmemCnt + + if { $haveMem } { destroy .m.e } + + # Create Memory Structure + frame .m.e + set haveMem 1 + pack .m.e -in .m -side top -anchor w + # Now fill it with values + for {set i 0} {$i < $memCnt} {incr i 16} { + set addr [expr $minAddr + $i] + + frame .m.e.r$i + pack .m.e.r$i -side bottom -in .m.e + label .m.e.r$i.lab -width 6 -font $dpyFont -text [format "0x%.3x-" [expr $addr / 16]] + pack .m.e.r$i.lab -in .m.e.r$i -side left + + for {set j 0} {$j < 16} {incr j 8} { + set a [expr $addr + $j] + label .m.e.v$a -width 16 -font $dpyFont -relief ridge \ + -bg $normalBg + pack .m.e.v$a -in .m.e.r$i -side left + } + } +} + +proc setMem {Addr Val} { + global minAddr memCnt + if {$Addr < $minAddr || $Addr > [expr $minAddr + $memCnt]} { + error "Memory address $Addr out of range" + } + .m.e.v$Addr config -text [format %16x $Val] +} + +proc clearMem {} { + destroy .m.e + createMem 0 0 +} + + + +############################################################################### +# Command Line Initialization # +############################################################################### + +# Get code file name from input + +# Find file with specified extension +proc findFile {tlist ext} { + foreach t $tlist { + if {[string match "*.$ext" $t]} {return $t} + } + return "" +} + + +set codeFile [findFile $argv yo] +if {$codeFile != ""} { loadCode $codeFile} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq-full.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq-full.hcl new file mode 100644 index 00000000..0c946dd9 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq-full.hcl @@ -0,0 +1,224 @@ +#/* $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 ' +quote '#include "isa.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'word_t gen_pc(){return 0;}' +quote 'int main(int argc, char *argv[])' +quote ' {plusmode=0;return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' +# Instruction code for iaddq instruction +wordsig IIADDQ 'I_IADDQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced explicitly ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ##### +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic #################### + +##### Fetch stage inputs ##### +wordsig pc 'pc' # Program counter +##### Fetch stage computations ##### +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig icode 'icode' # Instruction control code +wordsig ifun 'ifun' # Instruction function +wordsig rA 'ra' # rA field from instruction +wordsig rB 'rb' # rB field from instruction +wordsig valC 'valc' # Constant from instruction +wordsig valP 'valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Decode stage computations ##### +wordsig valA 'vala' # Value from register A port +wordsig valB 'valb' # Value from register B port + +##### Execute stage computations ##### +wordsig valE 'vale' # Value computed by ALU +boolsig Cnd 'cond' # Branch test + +##### Memory stage computations ##### +wordsig valM 'valm' # Value read from memory +boolsig dmem_error 'dmem_error' # Error signal from data memory + + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +# Determine instruction code +word icode = [ + imem_error: INOP; + 1: imem_icode; # Default: get from instruction memory +]; + +# Determine instruction function +word ifun = [ + imem_error: FNONE; + 1: imem_ifun; # Default: get from instruction memory +]; + +bool instr_valid = icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Does fetched instruction require a regid byte? +bool need_regids = + icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +################ Decode Stage ################################### + +## What register should be used as the A source? +word srcA = [ + icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : rA; + icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word srcB = [ + icode in { IOPQ, IRMMOVQ, IMRMOVQ } : rB; + icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word dstE = [ + icode in { IRRMOVQ } && Cnd : rB; + icode in { IIRMOVQ, IOPQ} : rB; + icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word dstM = [ + icode in { IMRMOVQ, IPOPQ } : rA; + 1 : RNONE; # Don't write any register +]; + +################ Execute Stage ################################### + +## Select input A to ALU +word aluA = [ + icode in { IRRMOVQ, IOPQ } : valA; + icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : valC; + icode in { ICALL, IPUSHQ } : -8; + icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : valB; + icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + icode == IOPQ : ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = icode in { IOPQ }; + +################ Memory Stage ################################### + +## Set read control signal +bool mem_read = icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = icode in { IRMMOVQ, IPUSHQ, ICALL }; + +## Select memory address +word mem_addr = [ + icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : valE; + icode in { IPOPQ, IRET } : valA; + # Other instructions don't need address +]; + +## Select memory input data +word mem_data = [ + # Value from register + icode in { IRMMOVQ, IPUSHQ } : valA; + # Return PC + icode == ICALL : valP; + # Default: Don't write anything +]; + +## Determine instruction status +word Stat = [ + imem_error || dmem_error : SADR; + !instr_valid: SINS; + icode == IHALT : SHLT; + 1 : SAOK; +]; + +################ Program Counter Update ############################ + +## What address should instruction be fetched at + +word new_pc = [ + # Call. Use instruction constant + icode == ICALL : valC; + # Taken branch. Use instruction constant + icode == IJXX && Cnd : valC; + # Completion of RET instruction. Use value from stack + icode == IRET : valM; + # Default: Use incremented PC + 1 : valP; +]; +#/* $end seq-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq-std.hcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq-std.hcl new file mode 100644 index 00000000..9ee68ad5 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq-std.hcl @@ -0,0 +1,217 @@ +#/* $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 ' +quote '#include "isa.h"' +quote '#include "sim.h"' +quote 'int sim_main(int argc, char *argv[]);' +quote 'word_t gen_pc(){return 0;}' +quote 'int main(int argc, char *argv[])' +quote ' {plusmode=0;return sim_main(argc,argv);}' + +#################################################################### +# Declarations. Do not change/remove/delete any of these # +#################################################################### + +##### Symbolic representation of Y86-64 Instruction Codes ############# +wordsig INOP 'I_NOP' +wordsig IHALT 'I_HALT' +wordsig IRRMOVQ 'I_RRMOVQ' +wordsig IIRMOVQ 'I_IRMOVQ' +wordsig IRMMOVQ 'I_RMMOVQ' +wordsig IMRMOVQ 'I_MRMOVQ' +wordsig IOPQ 'I_ALU' +wordsig IJXX 'I_JMP' +wordsig ICALL 'I_CALL' +wordsig IRET 'I_RET' +wordsig IPUSHQ 'I_PUSHQ' +wordsig IPOPQ 'I_POPQ' + +##### Symbolic represenations of Y86-64 function codes ##### +wordsig FNONE 'F_NONE' # Default function code + +##### Symbolic representation of Y86-64 Registers referenced explicitly ##### +wordsig RRSP 'REG_RSP' # Stack Pointer +wordsig RNONE 'REG_NONE' # Special value indicating "no register" + +##### ALU Functions referenced explicitly ##### +wordsig ALUADD 'A_ADD' # ALU should add its arguments + +##### Possible instruction status values ##### +wordsig SAOK 'STAT_AOK' # Normal execution +wordsig SADR 'STAT_ADR' # Invalid memory address +wordsig SINS 'STAT_INS' # Invalid instruction +wordsig SHLT 'STAT_HLT' # Halt instruction encountered + +##### Signals that can be referenced by control logic #################### + +##### Fetch stage inputs ##### +wordsig pc 'pc' # Program counter +##### Fetch stage computations ##### +wordsig imem_icode 'imem_icode' # icode field from instruction memory +wordsig imem_ifun 'imem_ifun' # ifun field from instruction memory +wordsig icode 'icode' # Instruction control code +wordsig ifun 'ifun' # Instruction function +wordsig rA 'ra' # rA field from instruction +wordsig rB 'rb' # rB field from instruction +wordsig valC 'valc' # Constant from instruction +wordsig valP 'valp' # Address of following instruction +boolsig imem_error 'imem_error' # Error signal from instruction memory +boolsig instr_valid 'instr_valid' # Is fetched instruction valid? + +##### Decode stage computations ##### +wordsig valA 'vala' # Value from register A port +wordsig valB 'valb' # Value from register B port + +##### Execute stage computations ##### +wordsig valE 'vale' # Value computed by ALU +boolsig Cnd 'cond' # Branch test + +##### Memory stage computations ##### +wordsig valM 'valm' # Value read from memory +boolsig dmem_error 'dmem_error' # Error signal from data memory + + +#################################################################### +# Control Signal Definitions. # +#################################################################### + +################ Fetch Stage ################################### + +# Determine instruction code +word icode = [ + imem_error: INOP; + 1: imem_icode; # Default: get from instruction memory +]; + +# Determine instruction function +word ifun = [ + imem_error: FNONE; + 1: imem_ifun; # Default: get from instruction memory +]; + +bool instr_valid = icode in + { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ, + IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ }; + +# Does fetched instruction require a regid byte? +bool need_regids = + icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, + IIRMOVQ, IRMMOVQ, IMRMOVQ }; + +# Does fetched instruction require a constant word? +bool need_valC = + icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL }; + +################ Decode Stage ################################### + +## What register should be used as the A source? +word srcA = [ + icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ } : rA; + icode in { IPOPQ, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the B source? +word srcB = [ + icode in { IOPQ, IRMMOVQ, IMRMOVQ } : rB; + icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't need register +]; + +## What register should be used as the E destination? +word dstE = [ + icode in { IRRMOVQ } && Cnd : rB; + icode in { IIRMOVQ, IOPQ} : rB; + icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP; + 1 : RNONE; # Don't write any register +]; + +## What register should be used as the M destination? +word dstM = [ + icode in { IMRMOVQ, IPOPQ } : rA; + 1 : RNONE; # Don't write any register +]; + +################ Execute Stage ################################### + +## Select input A to ALU +word aluA = [ + icode in { IRRMOVQ, IOPQ } : valA; + icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : valC; + icode in { ICALL, IPUSHQ } : -8; + icode in { IRET, IPOPQ } : 8; + # Other instructions don't need ALU +]; + +## Select input B to ALU +word aluB = [ + icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, + IPUSHQ, IRET, IPOPQ } : valB; + icode in { IRRMOVQ, IIRMOVQ } : 0; + # Other instructions don't need ALU +]; + +## Set the ALU function +word alufun = [ + icode == IOPQ : ifun; + 1 : ALUADD; +]; + +## Should the condition codes be updated? +bool set_cc = icode in { IOPQ }; + +################ Memory Stage ################################### + +## Set read control signal +bool mem_read = icode in { IMRMOVQ, IPOPQ, IRET }; + +## Set write control signal +bool mem_write = icode in { IRMMOVQ, IPUSHQ, ICALL }; + +## Select memory address +word mem_addr = [ + icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : valE; + icode in { IPOPQ, IRET } : valA; + # Other instructions don't need address +]; + +## Select memory input data +word mem_data = [ + # Value from register + icode in { IRMMOVQ, IPUSHQ } : valA; + # Return PC + icode == ICALL : valP; + # Default: Don't write anything +]; + +## Determine instruction status +word Stat = [ + imem_error || dmem_error : SADR; + !instr_valid: SINS; + icode == IHALT : SHLT; + 1 : SAOK; +]; + +################ Program Counter Update ############################ + +## What address should instruction be fetched at + +word new_pc = [ + # Call. Use instruction constant + icode == ICALL : valC; + # Taken branch. Use instruction constant + icode == IJXX && Cnd : valC; + # Completion of RET instruction. Use value from stack + icode == IRET : valM; + # Default: Use incremented PC + 1 : valP; +]; +#/* $end seq-all-hcl */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq.tcl b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq.tcl new file mode 100644 index 00000000..2917a36f --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/seq.tcl @@ -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 " "%r9 " "%r10" "%r11" "%r12" "%r13" "%r14" ""] + +# Create rows of register labels and displays +for {set j 0} {$j < 3} {incr j 1} { + frame .r.labels$j + pack .r.labels$j -side top -in .r + + for {set c 0} {$c < 5} {incr c 1} { + set i [expr $j * 5 + $c] + label .r.lab$i -width 16 -font $dpyFont -text [lindex $regnames $i] + pack .r.lab$i -in .r.labels$j -side left + } + + # Create Row of Register Entries + frame .r.row$j + pack .r.row$j -side top -in .r + + # Create 5 registers + for {set c 0} {$c < 5} {incr c 1} { + set i [expr $j * 5 + $c] + if {$i == 15} { + label .r.reg$i -width 16 -font $dpyFont -text "" + } else { + label .r.reg$i -width 16 -font $dpyFont -relief ridge \ + -bg $normalBg + } + pack .r.reg$i -in .r.row$j -side left + } + +} + +############################################################################## +# Main Control Panel # +############################################################################## + +# +# Set the simulator name (defined in simname in ssim.c) +# as the title of the main window +# +wm title . $simname + +# Control Panel for simulator +set cntlBW 11 +frame .cntl +pack .cntl +button .cntl.quit -width $cntlBW -text Quit -command exit +button .cntl.run -width $cntlBW -text Go -command simGo +button .cntl.stop -width $cntlBW -text Stop -command simStop +button .cntl.step -width $cntlBW -text Step -command simStep +button .cntl.reset -width $cntlBW -text Reset -command simResetAll +pack .cntl.quit .cntl.run .cntl.stop .cntl.step .cntl.reset -in .cntl -side left +# Simulation speed control +scale .spd -label {Simulator Speed (10*log Hz)} -from -10 -to 30 -length 10c \ + -orient horizontal -command setSpeed +pack .spd + +# Simulation mode +set simMode forward + +# frame .md +# pack .md +# radiobutton .md.wedged -text Wedged -variable simMode \ +# -value wedged -width 10 -command {setSimMode wedged} +# radiobutton .md.stall -text Stall -variable simMode \ +# -value stall -width 10 -command {setSimMode stall} +# radiobutton .md.forward -text Forward -variable simMode \ +# -value forward -width 10 -command {setSimMode forward} +# pack .md.wedged .md.stall .md.forward -in .md -side left + +# simDelay defines #milliseconds for each cycle of simulator +# Initial value is 1000ms +set simDelay 1000 +# Set delay based on rate expressed in log(Hz) +proc setSpeed {rate} { + global simDelay + set simDelay [expr round(1000 / pow(10,$rate/10.0))] +} + +# Global variables controlling simulator execution +# Should simulator be running now? +set simGoOK 0 + +proc simStop {} { + global simGoOK + set simGoOK 0 +} + +proc simStep {} { + global simStat + set simStat [simRun 1] +} + +proc simGo {} { + global simGoOK simDelay simStat + set simGoOK 1 + # Disable the Go and Step buttons + # Enable the Stop button + while {$simGoOK} { + # run the simulator 1 cycle + after $simDelay + set simStat [simRun 1] + if {$simStat != "AOK" && $simStat != "BUB"} {set simGoOK 0} + update + } + # Disable the Stop button + # Enable the Go and Step buttons +} + +############################################################################## +# Processor State display # +############################################################################## + +# Overall width of pipe register display +set procWidth 60 +set procHeight 1 +set labWidth 8 + +# Add labeled display to window +proc addDisp {win width name} { + global dpyFont labFont + set lname [string tolower $name] + frame $win.$lname + pack $win.$lname -in $win -side left + label $win.$lname.t -text $name -font $labFont + label $win.$lname.c -width $width -font $dpyFont -bg white -relief ridge + pack $win.$lname.t $win.$lname.c -in $win.$lname -side top + return [list $win.$lname.c] +} + +# Set text in display row +proc setDisp {wins txts} { + for {set i 0} {$i < [llength $wins] && $i < [llength $txts]} {incr i} { + set win [lindex $wins $i] + set txt [lindex $txts $i] + $win config -text $txt + } +} + +frame .p -width $procWidth +pack .p -in . -side bottom +label .p.lab -text "Processor State" -font $bigLabFont -height $sectionHeight +pack .p.lab -in .p -side top +label .p.pc -text "PC Update Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +#label .p.wb -text "Writeback Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.mem -text "Memory Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.ex -text "Execute Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.id -text "Decode Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +label .p.if -text "Fetch Stage" -height $procHeight -font $bigLabFont -width $procWidth -bg NavyBlue -fg White +# New PC +frame .p.npc +# Mem +frame .p.m +# Execute +frame .p.e +# Decode +frame .p.d +# Fetch +frame .p.f +# Old PC +frame .p.opc +pack .p.npc .p.pc .p.m .p.mem .p.e .p.ex .p.d .p.id .p.f .p.if .p.opc -in .p -side top -anchor w -expand 1 + +# Take list of lists, and transpose nesting +# Assumes all lists are of same length +proc ltranspose {inlist} { + set result {} + for {set i 0} {$i < [llength [lindex $inlist 0]]} {incr i} { + set nlist {} + for {set j 0} {$j < [llength $inlist]} {incr j} { + set ele [lindex [lindex $inlist $j] $i] + set nlist [concat $nlist [list $ele]] + } + set result [concat $result [list $nlist]] + } + return $result +} + +# Fields in PC displayed +# Total size = 16 +set pwins(OPC) [ltranspose [list [addDisp .p.opc 16 PC]]] + +# Fetch display +# Total size = 6+4+4+16+16 = 46 +set pwins(F) [ltranspose \ + [list [addDisp .p.f 6 Instr] \ + [addDisp .p.f 4 rA]\ + [addDisp .p.f 4 rB] \ + [addDisp .p.f 16 valC] \ + [addDisp .p.f 16 valP]]] + +# Decode Display +# Total size = 16+16+4+4+4+4 = 48 +set pwins(D) [ltranspose \ + [list \ + [addDisp .p.d 16 valA] \ + [addDisp .p.d 16 valB] \ + [addDisp .p.d 4 dstE] \ + [addDisp .p.d 4 dstM] \ + [addDisp .p.d 4 srcA] \ + [addDisp .p.d 4 srcB]]] + + + + +# Execute Display +# Total size = 3+16 = 19 +set pwins(E) [ltranspose \ + [list [addDisp .p.e 3 Cnd] \ + [addDisp .p.e 16 valE]]] + +# Memory Display +# Total size = 16 +set pwins(M) [ltranspose \ + [list [addDisp .p.m 16 valM]]] + +# New PC Display +# Total Size = 16 +set pwins(NPC) [ltranspose \ + [list [addDisp .p.npc 16 newPC]]] + +# update status line for specified proc register +proc updateStage {name txts} { + set Name [string toupper $name] + global pwins + set wins [lindex $pwins($Name) 0] + setDisp $wins $txts +} + +########################################################################## +# Instruction Display # +########################################################################## + +toplevel .c +wm title .c "Program Code" +frame .c.cntl +pack .c.cntl -in .c -side top -anchor w +label .c.filelab -width 10 -text "File" +entry .c.filename -width 20 -relief sunken -textvariable codeFile \ + -font $dpyFont -bg white +button .c.loadbutton -width $cntlBW -command {loadCode $codeFile} -text Load +pack .c.filelab .c.filename .c.loadbutton -in .c.cntl -side left + +proc clearCode {} { + simLabel {} {} + destroy .c.t + destroy .c.tr +} + +proc createCode {} { + # Create Code Structure + frame .c.t + pack .c.t -in .c -side top -anchor w + frame .c.tr + pack .c.tr -in .c.t -side top -anchor nw +} + +proc loadCode {file} { + # Kill old code window + clearCode + # Create new one + createCode + simCode $file + simResetAll +} + +# Start with initial code window, even though it will be destroyed. +createCode + +# Add a line of code to the display +proc addCodeLine {line addr op text} { + global codeRowCount + # Create new line in display + global codeFont + frame .c.tr.$addr + pack .c.tr.$addr -in .c.tr -side top -anchor w + label .c.tr.$addr.a -width 6 -text [format "0x%x" $addr] -font $codeFont + label .c.tr.$addr.i -width 20 -text $op -font $codeFont + label .c.tr.$addr.s -width 2 -text "" -font $codeFont -bg white + label .c.tr.$addr.t -text $text -font $codeFont + pack .c.tr.$addr.a .c.tr.$addr.i .c.tr.$addr.s \ + .c.tr.$addr.t -in .c.tr.$addr -side left +} + +# Keep track of which instructions have stage labels + +set oldAddr {} + +proc simLabel {addrs labs} { + global oldAddr + set newAddr {} + # Clear away any old labels + foreach a $oldAddr { + .c.tr.$a.s config -text "" + } + for {set i 0} {$i < [llength $addrs]} {incr i} { + set a [lindex $addrs $i] + set t [lindex $labs $i] + if {[winfo exists .c.tr.$a]} { + .c.tr.$a.s config -text $t + set newAddr [concat $newAddr $a] + } + } + set oldAddr $newAddr +} + +proc simResetAll {} { + global simStat + set simStat "AOK" + simReset + simLabel {} {} + clearMem +} + +############################################################################### +# Memory Display # +############################################################################### +toplevel .m +wm title .m "Memory Contents" +frame .m.t +pack .m.t -in .m -side top -anchor w + +label .m.t.lab -width 6 -font $dpyFont -text " " +pack .m.t.lab -in .m.t -side left +for {set i 0} {$i < 16} {incr i 8} { + label .m.t.a$i -width 16 -font $dpyFont -text [format " 0x---%x" [expr $i % 16]] + pack .m.t.a$i -in .m.t -side left +} + + +# Keep track of range of addresses currently displayed +set minAddr 0 +set memCnt 0 +set haveMem 0 + +proc createMem {nminAddr nmemCnt} { + global minAddr memCnt haveMem codeFont dpyFont normalBg + set minAddr $nminAddr + set memCnt $nmemCnt + + if { $haveMem } { destroy .m.e } + + # Create Memory Structure + frame .m.e + set haveMem 1 + pack .m.e -in .m -side top -anchor w + # Now fill it with values + for {set i 0} {$i < $memCnt} {incr i 16} { + set addr [expr $minAddr + $i] + + frame .m.e.r$i + pack .m.e.r$i -side bottom -in .m.e + label .m.e.r$i.lab -width 6 -font $dpyFont -text [format "0x%.3x-" [expr $addr / 16]] + pack .m.e.r$i.lab -in .m.e.r$i -side left + + for {set j 0} {$j < 16} {incr j 8} { + set a [expr $addr + $j] + label .m.e.v$a -width 16 -font $dpyFont -relief ridge \ + -bg $normalBg + pack .m.e.v$a -in .m.e.r$i -side left + } + } +} + +proc setMem {Addr Val} { + global minAddr memCnt + if {$Addr < $minAddr || $Addr > [expr $minAddr + $memCnt]} { + error "Memory address $Addr out of range" + } + .m.e.v$Addr config -text [format %16x $Val] +} + +proc clearMem {} { + destroy .m.e + createMem 0 0 +} + + + +############################################################################### +# Command Line Initialization # +############################################################################### + +# Get code file name from input + +# Find file with specified extension +proc findFile {tlist ext} { + foreach t $tlist { + if {[string match "*.$ext" $t]} {return $t} + } + return "" +} + + +set codeFile [findFile $argv yo] +if {$codeFile != ""} { loadCode $codeFile} diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/sim.h b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/sim.h new file mode 100644 index 00000000..e5bf4857 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/sim.h @@ -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 + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/ssim.c b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/ssim.c new file mode 100644 index 00000000..4cae5a97 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/seq/ssim.c @@ -0,0 +1,1169 @@ +/*********************************************************************** + * + * ssim.c - Sequential Y86-64 simulator + * + * Copyright (c) 2002, 2015. Bryant and D. O'Hallaron, All rights reserved. + * May not be used, modified, or copied without permission. + ***********************************************************************/ + +#include +#include +#include +#include +#include +#include "isa.h" +#include "sim.h" + +#define MAXBUF 1024 + +#ifdef HAS_GUI +#include +#endif /* HAS_GUI */ + +#define MAXARGS 128 +#define MAXBUF 1024 +#define TKARGS 3 + +/*************** + * Begin Globals + ***************/ + +/* Simulator name defined and initialized by the compiled HCL file */ +/* according to the -n argument supplied to hcl2c */ +extern char simname[]; + +/* SEQ=0, SEQ+=1. Modified by HCL main() */ +int plusmode = 0; + +/* Parameters modifed by the command line */ +int gui_mode = FALSE; /* Run in GUI mode instead of TTY mode? (-g) */ +char *object_filename; /* The input object file name. */ +FILE *object_file; /* Input file handle */ +bool_t verbosity = 2; /* Verbosity level [TTY only] (-v) */ +word_t instr_limit = 10000; /* Instruction limit [TTY only] (-l) */ +bool_t do_check = FALSE; /* Test with YIS? [TTY only] (-t) */ + +/************* + * End Globals + *************/ + + +/*************************** + * Begin function prototypes + ***************************/ + +static void usage(char *name); /* Print helpful usage message */ +static void run_tty_sim(); /* Run simulator in TTY mode */ + +#ifdef HAS_GUI +void addAppCommands(Tcl_Interp *interp); /* Add application-dependent commands */ +#endif /* HAS_GUI */ + +/************************* + * End function prototypes + *************************/ + + +/******************************************************************* + * Part 1: This part is the initial entry point that handles general + * initialization. It parses the command line and does any necessary + * setup to run in either TTY or GUI mode, and then starts the + * simulation. + *******************************************************************/ + +/* + * sim_main - main simulator routine. This function is called from the + * main() routine in the HCL file. + */ +int sim_main(int argc, char **argv) +{ + int i; + int c; + char *myargv[MAXARGS]; + + + /* Parse the command line arguments */ + while ((c = getopt(argc, argv, "htgl:v:")) != -1) { + switch(c) { + case 'h': + usage(argv[0]); + break; + case 'l': + instr_limit = atoll(optarg); + break; + case 'v': + verbosity = atoi(optarg); + if (verbosity < 0 || verbosity > 2) { + printf("Invalid verbosity %d\n", verbosity); + usage(argv[0]); + } + break; + case 't': + do_check = TRUE; + break; + case 'g': + gui_mode = TRUE; + break; + default: + printf("Invalid option '%c'\n", c); + usage(argv[0]); + break; + } + } + + + /* Do we have too many arguments? */ + if (optind < argc - 1) { + printf("Too many command line arguments:"); + for (i = optind; i < argc; i++) + printf(" %s", argv[i]); + printf("\n"); + usage(argv[0]); + } + + + /* The single unflagged argument should be the object file name */ + object_filename = NULL; + object_file = NULL; + if (optind < argc) { + object_filename = argv[optind]; + object_file = fopen(object_filename, "r"); + if (!object_file) { + fprintf(stderr, "Couldn't open object file %s\n", object_filename); + exit(1); + } + } + + + /* Run the simulator in GUI mode (-g flag) */ + if (gui_mode) { + +#ifndef HAS_GUI + printf("To run in GUI mode, you must recompile with the HAS_GUI constant defined.\n"); + exit(1); +#endif /* HAS_GUI */ + + /* In GUI mode, we must specify the object file on command line */ + if (!object_file) { + printf("Missing object file argument in GUI mode\n"); + usage(argv[0]); + } + + /* Build the command line for the GUI simulator */ + for (i = 0; i < TKARGS; i++) { + if ((myargv[i] = malloc(MAXBUF*sizeof(char))) == NULL) { + perror("malloc error"); + exit(1); + } + } + strcpy(myargv[0], argv[0]); + +#if 0 + printf("argv[0]=%s\n", argv[0]); + { + char buf[1000]; + getcwd(buf, 1000); + printf("cwd=%s\n", buf); + } +#endif + + if (plusmode == 0) /* SEQ */ + strcpy(myargv[1], "seq.tcl"); + else + strcpy(myargv[1], "seq+.tcl"); + strcpy(myargv[2], object_filename); + myargv[3] = NULL; + + /* Start the GUI simulator */ +#ifdef HAS_GUI + Tk_Main(TKARGS, myargv, Tcl_AppInit); +#endif /* HAS_GUI */ + exit(0); + } + + /* Otherwise, run the simulator in TTY mode (no -g flag) */ + run_tty_sim(); + + exit(0); +} + +/* + * run_tty_sim - Run the simulator in TTY mode + */ +static void run_tty_sim() +{ + word_t icount = 0; + status = STAT_AOK; + cc_t result_cc = 0; + word_t byte_cnt = 0; + mem_t mem0, reg0; + state_ptr isa_state = NULL; + + + /* In TTY mode, the default object file comes from stdin */ + if (!object_file) { + object_file = stdin; + } + + /* Initializations */ + if (verbosity >= 2) + sim_set_dumpfile(stdout); + sim_init(); + + /* Emit simulator name */ + printf("%s\n", simname); + + byte_cnt = load_mem(mem, object_file, 1); + if (byte_cnt == 0) { + fprintf(stderr, "No lines of code found\n"); + exit(1); + } else if (verbosity >= 2) { + printf("%lld bytes of code read\n", byte_cnt); + } + fclose(object_file); + if (do_check) { + isa_state = new_state(0); + free_mem(isa_state->r); + free_mem(isa_state->m); + isa_state->m = copy_mem(mem); + isa_state->r = copy_mem(reg); + isa_state->cc = cc; + } + + mem0 = copy_mem(mem); + reg0 = copy_mem(reg); + + + icount = sim_run(instr_limit, &status, &result_cc); + if (verbosity > 0) { + printf("%lld instructions executed\n", icount); + printf("Status = %s\n", stat_name(status)); + printf("Condition Codes: %s\n", cc_name(result_cc)); + printf("Changed Register State:\n"); + diff_reg(reg0, reg, stdout); + printf("Changed Memory State:\n"); + diff_mem(mem0, mem, stdout); + } + if (do_check) { + byte_t e = STAT_AOK; + int step; + bool_t match = TRUE; + + for (step = 0; step < instr_limit && e == STAT_AOK; step++) { + e = step_state(isa_state, stdout); + } + + if (diff_reg(isa_state->r, reg, NULL)) { + match = FALSE; + if (verbosity > 0) { + printf("ISA Register != Pipeline Register File\n"); + diff_reg(isa_state->r, reg, stdout); + } + } + if (diff_mem(isa_state->m, mem, NULL)) { + match = FALSE; + if (verbosity > 0) { + printf("ISA Memory != Pipeline Memory\n"); + diff_mem(isa_state->m, mem, stdout); + } + } + if (isa_state->cc != result_cc) { + match = FALSE; + if (verbosity > 0) { + printf("ISA Cond. Codes (%s) != Pipeline Cond. Codes (%s)\n", + cc_name(isa_state->cc), cc_name(result_cc)); + } + } + if (match) { + printf("ISA Check Succeeds\n"); + } else { + printf("ISA Check Fails\n"); + } + } +} + + + +/* + * usage - print helpful diagnostic information + */ +static void usage(char *name) +{ + printf("Usage: %s [-htg] [-l m] [-v n] file.yo\n", name); + printf("file.yo required in GUI mode, optional in TTY mode (default stdin)\n"); + printf(" -h Print this message\n"); + printf(" -g Run in GUI mode instead of TTY mode (default TTY)\n"); + printf(" -l m Set instruction limit to m [TTY mode only] (default %lld)\n", instr_limit); + printf(" -v n Set verbosity level to 0 <= n <= 2 [TTY mode only] (default %d)\n", verbosity); + printf(" -t Test result against ISA simulator (yis) [TTY mode only]\n"); + exit(0); +} + + + +/********************************************************* + * Part 2: This part contains the core simulator routines. + *********************************************************/ + +/********************** + * Begin Part 2 Globals + **********************/ + +/* + * Variables related to hardware units in the processor + */ +mem_t mem; /* Instruction and data memory */ +word_t minAddr = 0; +word_t memCnt = 0; + +/* Other processor state */ +mem_t reg; /* Register file */ +cc_t cc = DEFAULT_CC; /* Condition code register */ +cc_t cc_in = DEFAULT_CC; /* Input to condition code register */ + +/* + * SEQ+: Results computed by previous instruction. + * Used to compute PC in current instruction + */ +byte_t prev_icode = I_NOP; +byte_t prev_ifun = 0; +word_t prev_valc = 0; +word_t prev_valm = 0; +word_t prev_valp = 0; +bool_t prev_bcond = FALSE; + +byte_t prev_icode_in = I_NOP; +byte_t prev_ifun_in = 0; +word_t prev_valc_in = 0; +word_t prev_valm_in = 0; +word_t prev_valp_in = 0; +bool_t prev_bcond_in = FALSE; + + +/* Program Counter */ +word_t pc = 0; /* Program counter value */ +word_t pc_in = 0;/* Input to program counter */ + +/* Intermediate values */ +byte_t imem_icode = I_NOP; +byte_t imem_ifun = F_NONE; +byte_t icode = I_NOP; +word_t ifun = 0; +byte_t instr = HPACK(I_NOP, F_NONE); +word_t ra = REG_NONE; +word_t rb = REG_NONE; +word_t valc = 0; +word_t valp = 0; +bool_t imem_error; +bool_t instr_valid; + +word_t srcA = REG_NONE; +word_t srcB = REG_NONE; +word_t destE = REG_NONE; +word_t destM = REG_NONE; +word_t vala = 0; +word_t valb = 0; +word_t vale = 0; + +bool_t bcond = FALSE; +bool_t cond = FALSE; +word_t valm = 0; +bool_t dmem_error; + +bool_t mem_write = FALSE; +word_t mem_addr = 0; +word_t mem_data = 0; +byte_t status = STAT_AOK; + + +/* Values computed by control logic */ +word_t gen_pc(); /* SEQ+ */ +word_t gen_icode(); +word_t gen_ifun(); +word_t gen_need_regids(); +word_t gen_need_valC(); +word_t gen_instr_valid(); +word_t gen_srcA(); +word_t gen_srcB(); +word_t gen_dstE(); +word_t gen_dstM(); +word_t gen_aluA(); +word_t gen_aluB(); +word_t gen_alufun(); +word_t gen_set_cc(); +word_t gen_mem_addr(); +word_t gen_mem_data(); +word_t gen_mem_read(); +word_t gen_mem_write(); +word_t gen_Stat(); +word_t gen_new_pc(); + +/* Log file */ +FILE *dumpfile = NULL; + +#ifdef HAS_GUI +/* Representations of digits */ +static char digits[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; +#endif /* HAS_GUI */ + +/******************** + * End Part 2 Globals + ********************/ + +#ifdef HAS_GUI + +/* Create string in hex/oct/binary format with leading zeros */ +/* bpd denotes bits per digit Should be in range 1-4, + bpw denotes bits per word.*/ +void wstring(uword_t x, int bpd, int bpw, char *str) +{ + int digit; + uword_t mask = ((uword_t) 1 << bpd) - 1; + for (digit = (bpw-1)/bpd; digit >= 0; digit--) { + uword_t val = (x >> (digit * bpd)) & mask; + *str++ = digits[val]; + } + *str = '\0'; +} + +/* used for formatting instructions */ +static char status_msg[128]; + +/* SEQ+ */ +static char *format_prev() +{ + char istring[17]; + char mstring[17]; + char pstring[17]; + wstring(prev_valc, 4, 64, istring); + wstring(prev_valm, 4, 64, mstring); + wstring(prev_valp, 4, 64, pstring); + sprintf(status_msg, "%c %s %s %s %s", + prev_bcond ? 'Y' : 'N', + iname(HPACK(prev_icode, prev_ifun)), + istring, mstring, pstring); + + return status_msg; +} + +static char *format_pc() +{ + char pstring[17]; + wstring(pc, 4, 64, pstring); + sprintf(status_msg, "%s", pstring); + return status_msg; +} + +static char *format_f() +{ + char valcstring[17]; + char valpstring[17]; + wstring(valc, 4, 64, valcstring); + wstring(valp, 4, 64, valpstring); + sprintf(status_msg, "%s %s %s %s %s", + iname(HPACK(icode, ifun)), + reg_name(ra), + reg_name(rb), + valcstring, + valpstring); + return status_msg; +} + +static char *format_d() +{ + char valastring[17]; + char valbstring[17]; + wstring(vala, 4, 64, valastring); + wstring(valb, 4, 64, valbstring); + sprintf(status_msg, "%s %s %s %s %s %s", + valastring, + valbstring, + reg_name(destE), + reg_name(destM), + reg_name(srcA), + reg_name(srcB)); + + return status_msg; +} + +static char *format_e() +{ + char valestring[17]; + wstring(vale, 4, 64, valestring); + sprintf(status_msg, "%c %s", + bcond ? 'Y' : 'N', + valestring); + return status_msg; +} + +static char *format_m() +{ + char valmstring[17]; + wstring(valm, 4, 64, valmstring); + sprintf(status_msg, "%s", valmstring); + return status_msg; +} + +static char *format_npc() +{ + char npcstring[17]; + wstring(pc_in, 4, 64, npcstring); + sprintf(status_msg, "%s", npcstring); + return status_msg; +} +#endif /* HAS_GUI */ + +/* Report system state */ +static void sim_report() { + +#ifdef HAS_GUI + if (gui_mode) { + report_pc(pc); + if (plusmode) { + report_state("PREV", format_prev()); + report_state("PC", format_pc()); + } else { + report_state("OPC", format_pc()); + } + report_state("F", format_f()); + report_state("D", format_d()); + report_state("E", format_e()); + report_state("M", format_m()); + if (!plusmode) { + report_state("NPC", format_npc()); + } + show_cc(cc); + } +#endif /* HAS_GUI */ + +} + +static int initialized = 0; +void sim_init() +{ + + /* Create memory and register files */ + initialized = 1; + mem = init_mem(MEM_SIZE); + reg = init_reg(); + sim_reset(); + clear_mem(mem); +} + +void sim_reset() +{ + if (!initialized) + sim_init(); + clear_mem(reg); + minAddr = 0; + memCnt = 0; + +#ifdef HAS_GUI + if (gui_mode) { + signal_register_clear(); + create_memory_display(); + sim_report(); + } +#endif + + if (plusmode) { + prev_icode = prev_icode_in = I_NOP; + prev_ifun = prev_ifun_in = 0; + prev_valc = prev_valc_in = 0; + prev_valm = prev_valm_in = 0; + prev_valp = prev_valp_in = 0; + prev_bcond = prev_bcond_in = FALSE; + pc = 0; + } else { + pc_in = 0; + } + cc = DEFAULT_CC; + cc_in = DEFAULT_CC; + destE = REG_NONE; + destM = REG_NONE; + mem_write = FALSE; + mem_addr = 0; + mem_data = 0; + + /* Reset intermediate values to clear display */ + icode = I_NOP; + ifun = 0; + instr = HPACK(I_NOP, F_NONE); + ra = REG_NONE; + rb = REG_NONE; + valc = 0; + valp = 0; + + srcA = REG_NONE; + srcB = REG_NONE; + destE = REG_NONE; + destM = REG_NONE; + vala = 0; + valb = 0; + vale = 0; + + cond = FALSE; + bcond = FALSE; + valm = 0; + + sim_report(); +} + +/* Update the processor state */ +static void update_state() +{ + if (plusmode) { + prev_icode = prev_icode_in; + prev_ifun = prev_ifun_in; + prev_valc = prev_valc_in; + prev_valm = prev_valm_in; + prev_valp = prev_valp_in; + prev_bcond = prev_bcond_in; + } else { + pc = pc_in; + } + cc = cc_in; + /* Writeback */ + if (destE != REG_NONE) + set_reg_val(reg, destE, vale); + if (destM != REG_NONE) + set_reg_val(reg, destM, valm); + + if (mem_write) { + /* Should have already tested this address */ + set_word_val(mem, mem_addr, mem_data); + sim_log("Wrote 0x%llx to address 0x%llx\n", mem_data, mem_addr); +#ifdef HAS_GUI + if (gui_mode) { + if (mem_addr % 8 != 0) { + /* Just did a misaligned write. + Need to display both words */ + word_t align_addr = mem_addr & ~0x3; + word_t val; + get_word_val(mem, align_addr, &val); + set_memory(align_addr, val); + align_addr+=8; + get_word_val(mem, align_addr, &val); + set_memory(align_addr, val); + } else { + set_memory(mem_addr, mem_data); + } + } +#endif /* HAS_GUI */ + } +} + +/* Execute one instruction */ +/* Return resulting status */ +static byte_t sim_step() +{ + word_t aluA; + word_t aluB; + word_t alufun; + + status = STAT_AOK; + imem_error = dmem_error = FALSE; + + update_state(); /* Update state from last cycle */ + + if (plusmode) { + pc = gen_pc(); + } + valp = pc; + instr = HPACK(I_NOP, F_NONE); + imem_error = !get_byte_val(mem, valp, &instr); + if (imem_error) { + sim_log("Couldn't fetch at address 0x%llx\n", valp); + } + imem_icode = HI4(instr); + imem_ifun = LO4(instr); + icode = gen_icode(); + ifun = gen_ifun(); + instr_valid = gen_instr_valid(); + valp++; + if (gen_need_regids()) { + byte_t regids; + if (get_byte_val(mem, valp, ®ids)) { + ra = GET_RA(regids); + rb = GET_RB(regids); + } else { + ra = REG_NONE; + rb = REG_NONE; + status = STAT_ADR; + sim_log("Couldn't fetch at address 0x%llx\n", valp); + } + valp++; + } else { + ra = REG_NONE; + rb = REG_NONE; + } + + if (gen_need_valC()) { + if (get_word_val(mem, valp, &valc)) { + } else { + valc = 0; + status = STAT_ADR; + sim_log("Couldn't fetch at address 0x%llx\n", valp); + } + valp+=8; + } else { + valc = 0; + } + sim_log("IF: Fetched %s at 0x%llx. ra=%s, rb=%s, valC = 0x%llx\n", + iname(HPACK(icode,ifun)), pc, reg_name(ra), reg_name(rb), valc); + + if (status == STAT_AOK && icode == I_HALT) { + status = STAT_HLT; + } + + srcA = gen_srcA(); + if (srcA != REG_NONE) { + vala = get_reg_val(reg, srcA); + } else { + vala = 0; + } + + srcB = gen_srcB(); + if (srcB != REG_NONE) { + valb = get_reg_val(reg, srcB); + } else { + valb = 0; + } + + cond = cond_holds(cc, ifun); + + destE = gen_dstE(); + destM = gen_dstM(); + + aluA = gen_aluA(); + aluB = gen_aluB(); + alufun = gen_alufun(); + vale = compute_alu(alufun, aluA, aluB); + cc_in = cc; + if (gen_set_cc()) + cc_in = compute_cc(alufun, aluA, aluB); + + bcond = cond && (icode == I_JMP); + + mem_addr = gen_mem_addr(); + mem_data = gen_mem_data(); + + + if (gen_mem_read()) { + dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm); + if (dmem_error) { + sim_log("Couldn't read at address 0x%llx\n", mem_addr); + } + } else + valm = 0; + + mem_write = gen_mem_write(); + if (mem_write) { + /* Do a test read of the data memory to make sure address is OK */ + word_t junk; + dmem_error = dmem_error || !get_word_val(mem, mem_addr, &junk); + } + + status = gen_Stat(); + + if (plusmode) { + prev_icode_in = icode; + prev_ifun_in = ifun; + prev_valc_in = valc; + prev_valm_in = valm; + prev_valp_in = valp; + prev_bcond_in = bcond; + } else { + /* Update PC */ + pc_in = gen_new_pc(); + } + sim_report(); + return status; +} + +/* + Run processor until one of following occurs: + - An error status is encountered in WB. + - max_instr instructions have completed through WB + + Return number of instructions executed. + if statusp nonnull, then will be set to status of final instruction + if ccp nonnull, then will be set to condition codes of final instruction +*/ +word_t sim_run(word_t max_instr, byte_t *statusp, cc_t *ccp) +{ + word_t icount = 0; + byte_t run_status = STAT_AOK; + while (icount < max_instr) { + run_status = sim_step(); + icount++; + if (run_status != STAT_AOK) + break; + } + if (statusp) + *statusp = run_status; + if (ccp) + *ccp = cc; + return icount; +} + +/* If dumpfile set nonNULL, lots of status info printed out */ +void sim_set_dumpfile(FILE *df) +{ + dumpfile = df; +} + +/* + * sim_log dumps a formatted string to the dumpfile, if it exists + * accepts variable argument list + */ +void sim_log( const char *format, ... ) { + if (dumpfile) { + va_list arg; + va_start( arg, format ); + vfprintf( dumpfile, format, arg ); + va_end( arg ); + } +} + + +/************************************************************* + * Part 3: This part contains simulation control for the TK + * simulator. + *************************************************************/ + +#ifdef HAS_GUI + +/********************** + * Begin Part 3 globals + **********************/ + +/* Hack for SunOS */ +extern int matherr(); +int *tclDummyMathPtr = (int *) matherr; + +static char tcl_msg[256]; + +/* Keep track of the TCL Interpreter */ +static Tcl_Interp *sim_interp = NULL; + +static mem_t post_load_mem; + +/********************** + * End Part 3 globals + **********************/ + + +/* function prototypes */ +int simResetCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); +int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); +int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); +int simRunCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); +void addAppCommands(Tcl_Interp *interp); + +/****************************************************************************** + * tcl command definitions + ******************************************************************************/ + +/* Implement command versions of the simulation functions */ +int simResetCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + sim_interp = interp; + if (argc != 1) { + interp->result = "No arguments allowed"; + return TCL_ERROR; + } + sim_reset(); + if (post_load_mem) { + free_mem(mem); + mem = copy_mem(post_load_mem); + } + interp->result = stat_name(STAT_AOK); + return TCL_OK; +} + +int simLoadCodeCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + FILE *object_file; + word_t code_count; + sim_interp = interp; + if (argc != 2) { + interp->result = "One argument required"; + return TCL_ERROR; + } + object_file = fopen(argv[1], "r"); + if (!object_file) { + sprintf(tcl_msg, "Couldn't open code file '%s'", argv[1]); + interp->result = tcl_msg; + return TCL_ERROR; + } + sim_reset(); + code_count = load_mem(mem, object_file, 0); + post_load_mem = copy_mem(mem); + sprintf(tcl_msg, "%lld", code_count); + interp->result = tcl_msg; + fclose(object_file); + return TCL_OK; +} + +int simLoadDataCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + FILE *data_file; + word_t word_count = 0; + interp->result = "Not implemented"; + return TCL_ERROR; + + + sim_interp = interp; + if (argc != 2) { + interp->result = "One argument required"; + return TCL_ERROR; + } + data_file = fopen(argv[1], "r"); + if (!data_file) { + sprintf(tcl_msg, "Couldn't open data file '%s'", argv[1]); + interp->result = tcl_msg; + return TCL_ERROR; + } + sprintf(tcl_msg, "%lld", word_count); + interp->result = tcl_msg; + fclose(data_file); + return TCL_OK; +} + + +int simRunCmd(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + word_t step_limit = 1; + byte_t run_status; + cc_t cc; + sim_interp = interp; + if (argc > 2) { + interp->result = "At most one argument allowed"; + return TCL_ERROR; + } + if (argc >= 2 && + (sscanf(argv[1], "%lld", &step_limit) != 1 || + step_limit < 0)) { + sprintf(tcl_msg, "Cannot run for '%s' cycles!", argv[1]); + interp->result = tcl_msg; + return TCL_ERROR; + } + sim_run(step_limit, &run_status, &cc); + interp->result = stat_name(run_status); + return TCL_OK; +} + +/****************************************************************************** + * registering the commands with tcl + ******************************************************************************/ + +void addAppCommands(Tcl_Interp *interp) +{ + sim_interp = interp; + Tcl_CreateCommand(interp, "simReset", (Tcl_CmdProc *) simResetCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "simCode", (Tcl_CmdProc *) simLoadCodeCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "simData", (Tcl_CmdProc *) simLoadDataCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateCommand(interp, "simRun", (Tcl_CmdProc *) simRunCmd, + (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); +} + +/****************************************************************************** + * tcl functionality called from within C + ******************************************************************************/ + +/* Provide mechanism for simulator to update register display */ +void signal_register_update(reg_id_t r, word_t val) { + int code; + sprintf(tcl_msg, "setReg %d %lld 1", (int) r, (word_t) val); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to signal register set\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Provide mechanism for simulator to generate memory display */ +void create_memory_display() { + int code; + sprintf(tcl_msg, "createMem %lld %lld", minAddr, memCnt); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Command '%s' failed\n", tcl_msg); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } else { + word_t i; + for (i = 0; i < memCnt && code == TCL_OK; i+=8) { + word_t addr = minAddr+i; + word_t val; + if (!get_word_val(mem, addr, &val)) { + fprintf(stderr, "Out of bounds memory display\n"); + return; + } + sprintf(tcl_msg, "setMem %lld %lld", addr, val); + code = Tcl_Eval(sim_interp, tcl_msg); + } + if (code != TCL_OK) { + fprintf(stderr, "Couldn't set memory value\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } + } +} + +/* Provide mechanism for simulator to update memory value */ +void set_memory(word_t addr, word_t val) { + int code; + word_t nminAddr = minAddr; + word_t nmemCnt = memCnt; + + /* First see if we need to expand memory range */ + if (memCnt == 0) { + nminAddr = addr; + nmemCnt = 8; + } else if (addr < minAddr) { + nminAddr = addr; + nmemCnt = minAddr + memCnt - addr; + } else if (addr >= minAddr+memCnt) { + nmemCnt = addr-minAddr+8; + } + /* Now make sure nminAddr & nmemCnt are multiples of 16 */ + nmemCnt = ((nminAddr & 0xF) + nmemCnt + 0xF) & ~0xF; + nminAddr = nminAddr & ~0xF; + + if (nminAddr != minAddr || nmemCnt != memCnt) { + minAddr = nminAddr; + memCnt = nmemCnt; + create_memory_display(); + } else { + sprintf(tcl_msg, "setMem %lld %lld", addr, val); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Couldn't set memory value 0x%llx to 0x%llx\n", + addr, val); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } + } +} + +/* Provide mechanism for simulator to update condition code display */ +void show_cc(cc_t cc) +{ + int code; + sprintf(tcl_msg, "setCC %d %d %d", + GET_ZF(cc), GET_SF(cc), GET_OF(cc)); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to display condition codes\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Provide mechanism for simulator to clear register display */ +void signal_register_clear() { + int code; + code = Tcl_Eval(sim_interp, "clearReg"); + if (code != TCL_OK) { + fprintf(stderr, "Failed to signal register clear\n"); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Provide mechanism for simulator to report instructions as they are + read in +*/ + +void report_line(word_t line_no, word_t addr, char *hex, char *text) { + int code; + sprintf(tcl_msg, "addCodeLine %lld %lld {%s} {%s}", line_no, addr, hex, text); + code = Tcl_Eval(sim_interp, tcl_msg); + if (code != TCL_OK) { + fprintf(stderr, "Failed to report code line 0x%llx\n", addr); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + + +/* Provide mechanism for simulator to report which instruction + is being executed */ +void report_pc(word_t pc) +{ + int t_status; + char addr[18]; + char code[20]; + Tcl_DString cmd; + Tcl_DStringInit(&cmd); + Tcl_DStringAppend(&cmd, "simLabel ", -1); + Tcl_DStringStartSublist(&cmd); + sprintf(addr, "%llu", pc); + Tcl_DStringAppendElement(&cmd, addr); + + Tcl_DStringEndSublist(&cmd); + Tcl_DStringStartSublist(&cmd); + sprintf(code, "%s","*"); + Tcl_DStringAppend(&cmd, code, -1); + Tcl_DStringEndSublist(&cmd); + t_status = Tcl_Eval(sim_interp, Tcl_DStringValue(&cmd)); + if (t_status != TCL_OK) { + fprintf(stderr, "Failed to report code '%s'\n", code); + fprintf(stderr, "Error Message was '%s'\n", sim_interp->result); + } +} + +/* Report single line of stage state */ +void report_state(char *id, char *txt) +{ + int t_status; + sprintf(tcl_msg, "updateStage %s {%s}", id, txt); + t_status = Tcl_Eval(sim_interp, tcl_msg); + if (t_status != TCL_OK) { + fprintf(stderr, "Failed to report processor status\n"); + fprintf(stderr, "\tStage %s, status '%s'\n", + id, txt); + fprintf(stderr, "\tError Message was '%s'\n", sim_interp->result); + } +} + +/* + * Tcl_AppInit - Called by TCL to perform application-specific initialization. + */ +int Tcl_AppInit(Tcl_Interp *interp) +{ + /* Tell TCL about the name of the simulator so it can */ + /* use it as the title of the main window */ + Tcl_SetVar(interp, "simname", simname, TCL_GLOBAL_ONLY); + + if (Tcl_Init(interp) == TCL_ERROR) + return TCL_ERROR; + if (Tk_Init(interp) == TCL_ERROR) + return TCL_ERROR; + Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); + + /* Call procedure to add new commands */ + addAppCommands(interp); + + /* + * Specify a user-specific startup file to invoke if the application + * is run interactively. Typically the startup file is "~/.apprc" + * where "app" is the name of the application. If this line is deleted + * then no user-specific startup file will be run under any conditions. + */ + Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY); + return TCL_OK; + +} + + +#endif /* HAS_GUI */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/Makefile b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/Makefile new file mode 100644 index 00000000..a12aa947 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/Makefile @@ -0,0 +1,54 @@ +CC=gcc +CFLAGS=-Wall -O1 -g -fcommon -Wno-error + +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 diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/README b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/README new file mode 100644 index 00000000..e1f27fec --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/README @@ -0,0 +1,20 @@ +This directory contains examples of Y86-64 assembly code programs +(extension `.ys') used in Chapter 4 of CS:APP3e. + +Given an assembly code file "file.ys", you can assemble it with the +command "make file.yo". The resulting file is in the "object code" +format described in the book. + +You can assemble and simulate all the test programs in this directory. +First, you need to make the different simulators in the pipe (psim) +and seq (ssim and ssim+) directories. Then use the following +commands: + +PIPE: make testpsim +SEQ: make testssim +SEQ+: make testssim+ + +Each of these commands will cause a number of programs to be assembled +and simulated. Lots of things will scroll by, but you should see the message +"ISA Check Succeeds" for each of the programs tested. + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/abs-asum-cmov.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/abs-asum-cmov.ys new file mode 100644 index 00000000..de5ec7f6 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/abs-asum-cmov.ys @@ -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: diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/abs-asum-jmp.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/abs-asum-jmp.ys new file mode 100644 index 00000000..2951bfbb --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/abs-asum-jmp.ys @@ -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: diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asum.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asum.ys new file mode 100644 index 00000000..2c74f34b --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asum.ys @@ -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: diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asumi.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asumi.ys new file mode 100644 index 00000000..5821d062 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asumi.ys @@ -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: diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asumr.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asumr.ys new file mode 100644 index 00000000..7091271e --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/asumr.ys @@ -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 + jle return # If count <= 0, return 0 + pushq %rbx # Save callee-saved register + mrmovq (%rdi),%rbx # Get *start + irmovq $-1,%r10 + addq %r10,%rsi # count-- + irmovq $8,%r10 + addq %r10,%rdi # start++ + call rsum + addq %rbx,%rax # Add *start to sum + popq %rbx # Restore callee-saved register +return: + ret +/* $end rsum-ys */ + +# The stack starts here and grows to lower addresses + .pos 0x200 +stack: + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/cjr.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/cjr.ys new file mode 100644 index 00000000..a883b165 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/cjr.ys @@ -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 */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/j-cc.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/j-cc.ys new file mode 100644 index 00000000..e8a6eb39 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/j-cc.ys @@ -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 diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/poptest.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/poptest.ys new file mode 100644 index 00000000..236880d9 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/poptest.ys @@ -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 diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog1.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog1.ys new file mode 100644 index 00000000..f2f4dc5e --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog1.ys @@ -0,0 +1,8 @@ +# prog1: Pad with 3 nop's + irmovq $10,%rdx + irmovq $3,%rax + nop + nop + nop + addq %rdx,%rax + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog10.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog10.ys new file mode 100644 index 00000000..a5dc8c77 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog10.ys @@ -0,0 +1,7 @@ +# prog10 + irmovq $1,%rax + xorq %rsp,%rsp # Set stack pointer to 0 and CC to 100 + pushq %rax # Attempt to write to 0xfffffffffffffff8 + addq %rax,%rax # (Should not be executed) Would set CC to 000 + irmovq $2, %rax # Not executed + irmovq $3, %rax # Not executed diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog2.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog2.ys new file mode 100644 index 00000000..76634f0d --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog2.ys @@ -0,0 +1,7 @@ +# prog2: Pad with 2 nop's + irmovq $10,%rdx + irmovq $3,%rax + nop + nop + addq %rdx,%rax + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog3.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog3.ys new file mode 100644 index 00000000..08c9fe1a --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog3.ys @@ -0,0 +1,6 @@ +# prog3: Pad with 1 nop + irmovq $10,%rdx + irmovq $3,%rax + nop + addq %rdx,%rax + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog4.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog4.ys new file mode 100644 index 00000000..d9ca4ad0 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog4.ys @@ -0,0 +1,5 @@ +# prog4: No padding + irmovq $10,%rdx + irmovq $3,%rax + addq %rdx,%rax + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog5.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog5.ys new file mode 100644 index 00000000..3a9193c1 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog5.ys @@ -0,0 +1,8 @@ +# prog5: Load/use hazard + irmovq $128,%rdx + irmovq $3,%rcx + rmmovq %rcx, 0(%rdx) + irmovq $10,%rbx + mrmovq 0(%rdx), %rax # Load %rax + addq %rbx,%rax # Use %rax + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog6.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog6.ys new file mode 100644 index 00000000..c9db5bb0 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog6.ys @@ -0,0 +1,14 @@ +# Demonstration of return +# /* $begin prog6-ys */ +# prog6 + irmovq stack,%rsp # Initialize stack pointer + call proc # Procedure call + irmovq $10,%rdx # Return point + halt +.pos 0x20 +proc: # proc: + ret # Return immediately + rrmovq %rdx,%rbx # Not executed +.pos 0x30 +stack: # stack: Stack pointer +# /* $end prog6-ys */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog7.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog7.ys new file mode 100644 index 00000000..01702b39 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog7.ys @@ -0,0 +1,13 @@ +# Demonstrate branch cancellation +# /* $begin prog7-ys */ +# prog7 + xorq %rax,%rax + jne target # Not taken + irmovq $1, %rax # Fall through + halt +target: + irmovq $2, %rdx # Target + irmovq $3, %rbx # Target+1 +# /* $end prog7-ys */ + halt + diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog8.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog8.ys new file mode 100644 index 00000000..817518c8 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog8.ys @@ -0,0 +1,5 @@ +# prog8: Forwarding Priority + irmovq $10,%rdx + irmovq $3,%rdx + rrmovq %rdx,%rax + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog9.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog9.ys new file mode 100644 index 00000000..2dd364f9 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/prog9.ys @@ -0,0 +1,9 @@ +# Exception handling +# /* $begin prog9-yo */ + xorq %rax,%rax + jne target # Not taken + irmovq $1, %rax # Fall through + halt +target: + .byte 0xFF # Invalid instruction code +# /* $end prog9-yo */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/pushquestion.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/pushquestion.ys new file mode 100644 index 00000000..a0556325 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/pushquestion.ys @@ -0,0 +1,5 @@ + # Assembly Code to test semantics of pushq + irmovq 0x100, %rsp + pushq %rsp # Ambiguous + popq %rax + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/pushtest.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/pushtest.ys new file mode 100644 index 00000000..bdb5e634 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/pushtest.ys @@ -0,0 +1,7 @@ +# Test of Push semantics for Y86-64 + irmovq $0x100,%rsp # Initialize stack pointer + rrmovq %rsp,%rax # Save stack pointer + pushq %rsp # Push the stack pointer (old or new?) + popq %rdx # Get it back + subq %rdx,%rax # Compute difference. Either 0 (old) or 4 (new). + halt diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/ret-hazard.ys b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/ret-hazard.ys new file mode 100644 index 00000000..51add373 --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/starter/sim/y86-code/ret-hazard.ys @@ -0,0 +1,13 @@ +/* $begin ret-hazard-ys */ +# Test instruction that modifies %esp followed by ret + irmovq mem,%rbx + mrmovq 0(%rbx),%rsp # Sets %rsp to point to return point + ret # Returns to return point + halt # +rtnpt: irmovq $5,%rsi # Return point + halt +.pos 0x40 +mem: .quad stack # Holds desired stack pointer +.pos 0x50 +stack: .quad rtnpt # Top of stack: Holds return point +/* $end ret-hazard-ys */ diff --git a/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/task.md b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/task.md new file mode 100644 index 00000000..de69ffdb --- /dev/null +++ b/benchmarks/courselab_bench/data/cmu_15-213/task_architecture_lab/task.md @@ -0,0 +1,42 @@ +*********************** +The CS:APP Architecture Lab +Directions to Students +*********************** + +Goal: optimize the pipelined Y86-64 implementation so that the benchmark ncopy.ys runs correctly and achieves average CPE ≤ 10.5 on the provided pipeline simulator. + +What you must produce +--------------------- +Modify the code under sim/ as needed, then provide optimized sources in place (most commonly: +- sim/pipe/ncopy.ys (optimize the loop) +- optionally HCL files such as sim/pipe/pipe-*.hcl if you choose microarchitectural changes) + +Artifacts required for grading (already referenced in config.json): +- sim/pipe/ncopy.ys (always) +- sim/pipe/pipe-std.hcl, sim/pipe/pipe-full.hcl, sim/pipe/pipe-lf.hcl, sim/pipe/pipe-nt.hcl, sim/pipe/pipe-btfnt.hcl (if modified) + +Resources provided +------------------ +- sim/misc/: yas, yis, hcl2c, etc. +- sim/pipe/: pipeline simulator sources, HCL specs, benchmark/correctness scripts, baseline ncopy.ys +- sim/seq/: SEQ simulator sources (optional for reference) +- make targets: from sim/, run `make all GUIMODE= TKLIBS= TKINC=` to build TTY tools; from sim/pipe, run `make drivers` to regenerate drivers. + +How evaluation works +-------------------- +1) Setup builds TTY simulators (no GUI) and patches Makefiles for modern GCC. +2) Correctness: in sim/pipe, `./correctness.pl -q -p -f ncopy.ys` (pipeline mode). Must pass. +3) Performance: `./benchmark.pl -q -f ncopy.ys` is run; the Average CPE must be ≤ 10.5 (per lab rubric, full credit ≤ 7.5 but threshold set to 10.5 here). + +Tips +---- +- Start with ncopy.ys loop unrolling and strength reduction; measure with benchmark.pl. +- Use `make drivers` after changing ncopy.ys so the small/large drivers rebuild. +- `psim` is built in TTY mode; no Tcl/Tk needed. +- Keep code size reasonable (correctness.pl enforces byte limit default 1000). + +Submission checklist +-------------------- +- sim/pipe/ncopy.ys exists and assembles. +- correctness and benchmark scripts run without errors; Average CPE ≤ 10.5. +- Do not delete provided infra files (checked by checksums for benchmark/correctness scripts and tools). diff --git a/benchmarks/courselab_bench/data/courses.json b/benchmarks/courselab_bench/data/courses.json index bb61bf59..cc075c2e 100644 --- a/benchmarks/courselab_bench/data/courses.json +++ b/benchmarks/courselab_bench/data/courses.json @@ -6,6 +6,13 @@ "institution": "Demo University", "year": 2024, "num_tasks": 1 + }, + { + "course_id": "cmu_15-213", + "name": "Introduction to Computer Systems", + "institution": "Carnegie Mellon University", + "year": 2024, + "num_tasks": 1 } ] }