diff options
Diffstat (limited to 'sources/apps/SanityCheck')
| -rw-r--r-- | sources/apps/SanityCheck/.gitignore | 1 | ||||
| -rwxr-xr-x | sources/apps/SanityCheck/Makefile | 33 | ||||
| -rw-r--r-- | sources/apps/SanityCheck/sanity.cpp | 294 |
3 files changed, 328 insertions, 0 deletions
diff --git a/sources/apps/SanityCheck/.gitignore b/sources/apps/SanityCheck/.gitignore new file mode 100644 index 0000000..5f2829a --- /dev/null +++ b/sources/apps/SanityCheck/.gitignore @@ -0,0 +1 @@ +SoftMC_Sanity
\ No newline at end of file diff --git a/sources/apps/SanityCheck/Makefile b/sources/apps/SanityCheck/Makefile new file mode 100755 index 0000000..19e8a5c --- /dev/null +++ b/sources/apps/SanityCheck/Makefile @@ -0,0 +1,33 @@ +program_NAME := SoftMC_Sanity +program_CXX_SRCS := sanity.cpp $(wildcard ../../api/*.c) $(wildcard ../../api/*.cpp) +program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o} +program_CXX_OBJS := ${program_CXX_OBJS:.c=.o} +program_OBJS := $(program_CXX_OBJS) +program_INCLUDE_DIRS := ../../api ../../../boost-lib +program_LIBRARY_DIRS := +program_LIBRARIES := +CPPFLAGS += -g -std=c++11 -pthread -O3 + +CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) +LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) +LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) +LDFLAGS += -lboost_program_options + +CC=g++ + +.PHONY: all clean distclean + +all: $(program_NAME) + +$(program_NAME): $(program_OBJS) + $(CC) $(CPPFLAGS) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) + +clean: + @- $(RM) $(program_NAME) + @- $(RM) $(program_OBJS) + +parser: + $(MAKE) -C ../../api/lexyacc + cp ../../api/lexyacc/smc_parser . + +distclean: clean diff --git a/sources/apps/SanityCheck/sanity.cpp b/sources/apps/SanityCheck/sanity.cpp new file mode 100644 index 0000000..0c7b0f2 --- /dev/null +++ b/sources/apps/SanityCheck/sanity.cpp @@ -0,0 +1,294 @@ +#include <iostream> + +#include <boost/program_options.hpp> + +#include "instruction.h" +#include "prog.h" +#include "platform.h" + +using namespace std; +namespace po = boost::program_options; + +#define USE_SMC_FILE 0 + +#define NUM_ROWS_REG 8 +#define NUM_BANKS_REG 11 +#define CASR 0 +#define BASR 1 +#define RASR 2 + +#define PATTERN_REG 12 + +#define BAR 7 +#define RAR 6 +#define CAR 4 + +#define NUM_COLS_REG 14 +#define LOOP_COLS 13 + +#define TEMP_PATTERN_REG 15 + +/** + * @return an instruction formed by NOPs + */ +Inst all_nops() +{ + return __pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); +} + +int main(int argc, char* argv[]) +{ + uint num_banks, num_rows, num_cols; + + po::options_description help("General options"); + help.add_options()("help,h", "Display the help message\n"); + + po::options_description dram_org("DRAM organization options"); + dram_org.add_options() + ("num_banks", po::value<uint>(&num_banks)->required(), "Specify the number of banks in the chip") + ("num_rows", po::value<uint>(&num_rows )->required(), "Specify the number of rows per bank") + ("num_cols", po::value<uint>(&num_cols )->required(), "Specify the number of columns (cachelines) per row\n") + ; + + po::options_description all; + all.add(help).add(dram_org); + + po::variables_map vm; + try + { + po::store(po::parse_command_line(argc, argv, all), vm); + po::notify(vm); + } + catch(const po::error& e) + { + if (vm.count("help") || argc == 1) + { + std::cout << all << "\n"; + std::exit(1); + } + else + { + std::cerr << "CRITICAL: " << e.what() << std::endl; + std::cerr << " Use \"--help\" to view all options" << std::endl; + std::exit(1); + } + } + + SoftMCPlatform platform; + int err; + uint32_t wr_pattern; + // buffer allocated for reading data from the board + char* buf = (char*) malloc(sizeof(char)*32*1024); + + // Initialize the platform, opens file descriptors for the board PCI-E interface. + if((err = platform.init()) != SOFTMC_SUCCESS) + { + cerr << "Could not initialize SoftMC Platform: " << err << endl; + exit(-1); + } + // reset the board to hopefully restore the board's state + platform.reset_fpga(); + + Program program; + /* SoftMC programs are formed sequentially by adding + * instructions to the program one by one. Instructions + * can be added to the program using add_inst(). + */ + + program.add_inst(SMC_LI(num_rows, NUM_ROWS_REG)); // load NUM_ROWS into NUM_ROWS_REG + program.add_inst(SMC_LI(num_banks, NUM_BANKS_REG)); // load NUM_BANKS into NUM_BANKS_REG + + // Stride registers are used to increment the row,bank,column registers without + // using regular (non-DDR) instructions. This way the DRAM array can be traversed much faster + + program.add_inst(SMC_LI(8, CASR)); // Load 8 into CASR since each READ reads 8 columns + program.add_inst(SMC_LI(1, BASR)); // Load 1 into BASR + program.add_inst(SMC_LI(1, RASR)); // Load 1 into RASR + + // Initialize PRNG, this test will randomly generate + // the first data to write into DRAM, it will modify + // the data by cyclic shifting and multiplying it with itself + // during runtime (this will be further explained down below). + srand(time(NULL)+getpid()); + uint16_t rand1 = (uint16_t) rand(); + wr_pattern = rand1 << 16; + wr_pattern |= ((uint16_t)rand()); + printf("wr_pattern: %x\n", wr_pattern); + + // Load WR data into pattern register whose content + // will be replicated among all words in the wide register + // Wide register is a 512-bit register, its content will + // be written to DRAM with SMC_WR commands. + program.add_inst(SMC_LI(wr_pattern, PATTERN_REG)); + for(int i = 0 ; i < 16 ; i++) + program.add_inst(SMC_LDWD(PATTERN_REG,i)); + + program.add_inst(SMC_LI(0, BAR)); // Initialize BAR (bank address register) with 0 + + // add_label is used to add a label that can be used as a branch target to the program + program.add_label("BANK_BEGIN"); + + program.add_inst(SMC_LI(0, RAR)); // Initialize RAR with 0 + + program.add_label("ROW_BEGIN"); + + program.add_inst(SMC_LI(0, CAR)); // Initialize CAR with 0 + + // Four DRAM commands are issued at the same time + // to DRAM by SoftMC. + + // PREcharge bank BAR and wait for tRP (11 NOPs, 11 SoftMC cycles) + program.add_inst( + SMC_PRE(BAR, 0, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + program.add_inst(all_nops()); + program.add_inst(all_nops()); + + // ACT & wait for tRCD + program.add_inst( + SMC_ACT(BAR, 0, RAR, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + program.add_inst(all_nops()); + program.add_inst(all_nops()); + + // We are now going to loop over all 512-bits in the row + // Since each row is 2^13 bytes we need to WR 128 times + program.add_inst(SMC_LI(128,NUM_COLS_REG)); // Load COL_SIZE register + program.add_inst(SMC_LI(0,LOOP_COLS)); // Load loop variable + + /* + * Try to write a different pattern to each cache line + * in DRAM. + */ + program.add_label("WR_BEGIN"); + + // Write to a whole row, increment CAR per WR + program.add_inst( + SMC_WRITE(BAR, 0, CAR, 1, 0, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + + // Reload wide reg with the new data pattern + program.add_inst(SMC_SRC(PATTERN_REG,PATTERN_REG)); + for(int i = 0 ; i < 16 ; i++) + program.add_inst(SMC_LDWD(PATTERN_REG,i)); + + program.add_inst(SMC_ADDI(LOOP_COLS,1,LOOP_COLS)); + // add a branch lower instruction which will jump to WR_BEGIN + // as long as LOOP_COLS<NUM_COLS, to iterate over the whole row + program.add_branch(program.BR_TYPE::BL,LOOP_COLS,NUM_COLS_REG, "WR_BEGIN"); + // END "WR_BEGIN" LOOP + + // Add more randomness to the PATTERN_REG by multiplying it by 3 + // This happens when a row is written to + program.add_inst(SMC_MV(PATTERN_REG,TEMP_PATTERN_REG)); + program.add_inst(SMC_ADD(PATTERN_REG,TEMP_PATTERN_REG,PATTERN_REG)); + program.add_inst(SMC_ADD(PATTERN_REG,TEMP_PATTERN_REG,PATTERN_REG)); + for(int i = 0 ; i < 16 ; i++) + program.add_inst(SMC_LDWD(PATTERN_REG,i)); + + // Wait for t(write-precharge) + // & precharge the open bank + program.add_inst(all_nops()); + program.add_inst(all_nops()); + program.add_inst( + SMC_PRE(BAR, 0, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + + program.add_inst(SMC_LI(0, CAR)); // reload CAR we are now going to read the whole row + + // PRE & wait for tRP + program.add_inst( + SMC_PRE(BAR, 0, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + program.add_inst(all_nops()); + program.add_inst(all_nops()); + + // ACT & wait for tRCD + program.add_inst( + SMC_ACT(BAR, 0, RAR, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + program.add_inst(all_nops()); + program.add_inst(all_nops()); + + // Read from a whole row + // Essentially this can be imagined as an unrolled read whole row loop + for(int i = 0 ; i < num_cols ; i++){ + program.add_inst( + SMC_READ(BAR, 0, CAR, 1, 0, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + program.add_inst(all_nops()); + } + + // Wait for t(read-precharge) + // & precharge the open bank + program.add_inst(all_nops()); + program.add_inst(all_nops()); + program.add_inst( + SMC_PRE(BAR, 0, 0), + SMC_NOP(), SMC_NOP(), SMC_NOP() + ); + + // Increment row address by one since we are finished with this row + program.add_inst(SMC_ADDI(RAR,1,RAR)); + program.add_branch(program.BR_TYPE::BL,RAR,NUM_ROWS_REG, "ROW_BEGIN"); + program.add_inst(SMC_ADDI(BAR,1,BAR)); + program.add_branch(program.BR_TYPE::BL,BAR,NUM_BANKS_REG,"BANK_BEGIN"); + + program.add_inst(all_nops()); + program.add_inst(all_nops()); + program.add_inst(all_nops()); + program.add_inst(all_nops()); + + // Tells SoftMC that the user program has ended + program.add_inst(SMC_END()); + + // Transfer the program to the FPGA board + platform.execute(program); + + // Read count + int rc = 0; + + uint32_t pattern = wr_pattern; + uint64_t err_count = 0; + // Below loop reads continuously from the FPGA board + // since we know in what order we are issuing our reads + // we know what physical address they are reading + while(1) + { + platform.receiveData(buf, 64 * num_cols); // read one row each iteration + for(int j = 0 ; j < num_cols ; j++){ + // printf("Whole pattern for cacheline %d: %x\n", j, pattern); + for (int k = 0 ; k < 64 ; k++){ // each byte in cache line + uint8_t mini_patt = pattern >> ((uint32_t)(k%4)*8); + if(mini_patt != (uint8_t)buf[j*64 + k]){ + err_count++; + fprintf(stderr,"t1: Pattern mismatch! Bank: %d Row: %d CacheLine: %d Byte: %d Expect: %x Read: %x\n", + rc/(num_rows), rc%(num_rows), j, k, mini_patt, (uint8_t)buf[j*64 + k]); + } + } + + //shift pattern at each row iteration + uint32_t imd = pattern >> (uint32_t)1; + uint32_t imd2 = pattern << (uint32_t)31; + pattern = imd | imd2; + } + pattern = pattern*(uint32_t)3; + rc++; + if(rc % (num_rows) == 0) + printf("Bank %d finished!\n", rc/num_rows); + if(rc == num_rows*num_banks) + break; + } + + if (err_count != 0) + exit(-1); + else + return 0; +} |
