diff options
| -rw-r--r-- | sources/apps/case_studies/cs1_interleaving_pattern/Makefile | 33 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs1_interleaving_pattern/README.md | 10 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs1_interleaving_pattern/test.cpp | 435 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs1_interleaving_pattern/tools.h | 213 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs2_data_patterns/Makefile | 33 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs2_data_patterns/README.md | 11 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs2_data_patterns/test.cpp | 561 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs2_data_patterns/tools.h | 213 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs3_bitwise/Makefile | 33 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs3_bitwise/README.md | 23 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs3_bitwise/run_tests.sh | 12 | ||||
| -rw-r--r-- | sources/apps/case_studies/cs3_bitwise/test.cpp | 309 |
12 files changed, 1886 insertions, 0 deletions
diff --git a/sources/apps/case_studies/cs1_interleaving_pattern/Makefile b/sources/apps/case_studies/cs1_interleaving_pattern/Makefile new file mode 100644 index 0000000..953fe34 --- /dev/null +++ b/sources/apps/case_studies/cs1_interleaving_pattern/Makefile @@ -0,0 +1,33 @@ +program_NAME := TEST +program_CXX_SRCS := test.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)) + +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/case_studies/cs1_interleaving_pattern/README.md b/sources/apps/case_studies/cs1_interleaving_pattern/README.md new file mode 100644 index 0000000..43d7f32 --- /dev/null +++ b/sources/apps/case_studies/cs1_interleaving_pattern/README.md @@ -0,0 +1,10 @@ +## Case Study #1: RowHammer: Interleaving Pattern of Activations + +### Instructions + +1. run `make` to compile the DRAM Bender program +2. execute `./TEST <hc_per_aggr> <cascade_amount> <data_pattern_select> <out_filename>` to run the experiment + - hc_per_aggr: Total number of activation per aggressor row. + - cascade_amount: The number of consecutive activations for a aggressor row. Value 1 results with double-sided RH attack. + - data_pattern_select: selects the data pattern for victim and aggressor rows. + - out_filename: output filename for the results. The output file has the number of bitflips for each victim row. diff --git a/sources/apps/case_studies/cs1_interleaving_pattern/test.cpp b/sources/apps/case_studies/cs1_interleaving_pattern/test.cpp new file mode 100644 index 0000000..13646b5 --- /dev/null +++ b/sources/apps/case_studies/cs1_interleaving_pattern/test.cpp @@ -0,0 +1,435 @@ +#include "instruction.h" +#include "prog.h" +#include "platform.h" +#include "tools.h" + +#include <string> +#include <fstream> +#include <iostream> +#include <list> +#include <cassert> +#include <bitset> +#include <chrono> +#include <math.h> + +#include <array> +#include <algorithm> +#include <numeric> +#include <ctime> + +// #define PRINT_SOFTMC_PROGS + +using namespace std; + +#define CASR 0 +#define BASR 1 +#define RASR 2 + +#define NUM_SOFTMC_REGS 16 +#define FPGA_PERIOD 1.5015f // ns + +#define RED_TXT "\033[31m" +#define GREEN_TXT "\033[32m" +#define YELLOW_TXT "\033[33m" +#define BLUE_TXT "\033[34m" +#define MAGENTA_TXT "\033[35m" +#define NORMAL_TXT "\033[0m" + +int NUM_BANKS = 16; // this is the total number of banks in the chip +int NUM_BANK_GROUPS = 4; +int NUM_ROWS = 32768; +int ROW_SIZE = 8192; +int NUM_COLS_PER_ROW = 128; +int CHIP_NUM = 4; +int CACHE_LINE_BITS = 512; + +float DEFAULT_TRCD = 13.5f; // ns +float DEFAULT_TRAS = 35.0f; // ns +float DEFAULT_TRP = 13.5f; // ns +float DEFAULT_TWR = 15.0f; // ns +float DEFAULT_TRFC = 260.0f; // ns +float DEFAULT_TRRDS = 5.3f; // ns (ACT-ACT to different bank groups) +float DEFAULT_TRRDL = 6.4f; // ns (ACT-ACT to same bank group) +float DEFAULT_TREFI = 7800.0f; + +int trcd_cycles = (int) ceil(DEFAULT_TRCD/FPGA_PERIOD); +int tras_cycles = (int) ceil(DEFAULT_TRAS/FPGA_PERIOD); +int trp_cycles = (int) ceil(DEFAULT_TRP/FPGA_PERIOD); +int twr_cycles = (int) ceil(DEFAULT_TWR/FPGA_PERIOD); +int trfc_cycles = (int) ceil(DEFAULT_TRFC/FPGA_PERIOD); +int trrds_cycles = (int) ceil(DEFAULT_TRRDS/FPGA_PERIOD); +int trrdl_cycles = (int) ceil(DEFAULT_TRRDL/FPGA_PERIOD); +int trefi_cycles = (int) ceil(DEFAULT_TREFI/FPGA_PERIOD); + +bitset<512> vic_data_pattern, aggr_data_pattern; +vector<uint32_t> reserved_regs{CASR, BASR, RASR}; + +typedef struct RowSet { + vector<uint> victim_ids; + vector<uint> aggr_ids; + uint bank_id; +} RowSet; + +void init_program(Program& prog){ + add_op_with_delay(prog, SMC_PRE(0, 0, 1), 0, trp_cycles); // precharge all banks +} + +void end_program(Program& prog){ + prog.add_inst(all_nops()); + prog.add_inst(SMC_END()); +} + +void init_row(Program* prog, SoftMCRegAllocator* reg_alloc, const uint target_bank, const uint target_row, const bool is_victim){ + + SMC_REG reg_row_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_col_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_bank_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_num_cols = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_wrdata = reg_alloc->allocate_SMC_REG(); + + bitset<512> bitset_int_mask(0xFFFFFFFF); + bitset<512> data_pattern; + + if(is_victim) + data_pattern = vic_data_pattern; + else + data_pattern = aggr_data_pattern; + + prog->add_inst(SMC_LI(NUM_COLS_PER_ROW*8, reg_num_cols)); + prog->add_inst(SMC_LI(target_bank, reg_bank_addr)); + prog->add_inst(SMC_LI(target_row, reg_row_addr)); + prog->add_inst(SMC_LI(8, CASR)); + + // set up the input data in the wide register + for(int pos = 0; pos < 16; pos++){ + prog->add_inst(SMC_LI((((data_pattern >> 32*pos) & bitset_int_mask).to_ulong() & 0xFFFFFFFF), reg_wrdata)); + prog->add_inst(SMC_LDWD(reg_wrdata, pos)); + } + + // activate the target row + uint remaining = add_op_with_delay(*prog, SMC_ACT(reg_bank_addr, 0, reg_row_addr, 0), 0, trcd_cycles - 5); + + // write data to the row and precharge + prog->add_inst(SMC_LI(0, reg_col_addr)); + + string new_lbl = createSMCLabel("INIT_ROW"); + prog->add_label(new_lbl); + add_op_with_delay(*prog, SMC_WRITE(reg_bank_addr, 0, reg_col_addr, 1, 0, 0), 0, 0); + prog->add_branch(Program::BR_TYPE::BL, reg_col_addr, reg_num_cols, new_lbl); + + // precharge the open bank + add_op_with_delay(*prog, SMC_PRE(reg_bank_addr, 0, 0), 0, trp_cycles); + + reg_alloc->free_SMC_REG(reg_row_addr); + reg_alloc->free_SMC_REG(reg_col_addr); + reg_alloc->free_SMC_REG(reg_wrdata); + reg_alloc->free_SMC_REG(reg_bank_addr); + reg_alloc->free_SMC_REG(reg_num_cols); + +} + +void init_rs(Program* prog, SoftMCRegAllocator* reg_alloc, const RowSet rs) { + //init aggrs + for(auto aggr_id: rs.aggr_ids) + init_row(prog, reg_alloc, rs.bank_id, aggr_id, false); + //init victims + for(auto victim_id: rs.victim_ids) + init_row(prog, reg_alloc, rs.bank_id, victim_id, true); +} + +void hammer_rs(Program* prog, SoftMCRegAllocator* reg_alloc, const RowSet rs, + const uint hc_per_run, const uint num_runs){ + + SMC_REG reg_bank_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_row_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_num_hammers = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_cur_hammers = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_num_runs = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_cur_runs = reg_alloc->allocate_SMC_REG(); + + prog->add_inst(SMC_LI(rs.bank_id, reg_bank_addr)); + prog->add_inst(SMC_LI(hc_per_run, reg_num_hammers)); + prog->add_inst(SMC_LI(num_runs, reg_num_runs)); + + prog->add_inst(SMC_LI(0, reg_cur_runs)); + string lbl_hammer_run = createSMCLabel("HAMMER_RUN"); + prog->add_label(lbl_hammer_run); + + for(auto aggr_id: rs.aggr_ids){ + prog->add_inst(SMC_LI(aggr_id, reg_row_addr)); + prog->add_inst(SMC_LI(0, reg_cur_hammers)); + + string lbl_rh = createSMCLabel("ROWHAMMERING"); + prog->add_label(lbl_rh); + + uint remaining_cycs = add_op_with_delay(*prog, SMC_ACT(reg_bank_addr, 0, reg_row_addr, 0), 0, tras_cycles - 1); + remaining_cycs = add_op_with_delay(*prog, SMC_PRE(reg_bank_addr, 0, 0), remaining_cycs, 0); + + prog->add_inst(SMC_ADDI(reg_cur_hammers, 1, reg_cur_hammers)); + prog->add_branch(Program::BR_TYPE::BL, reg_cur_hammers, reg_num_hammers, lbl_rh); + + } + + prog->add_inst(SMC_ADDI(reg_cur_runs, 1, reg_cur_runs)); + prog->add_branch(Program::BR_TYPE::BL, reg_cur_runs, reg_num_runs, lbl_hammer_run); + + reg_alloc->free_SMC_REG(reg_bank_addr); + reg_alloc->free_SMC_REG(reg_row_addr); + reg_alloc->free_SMC_REG(reg_num_hammers); + reg_alloc->free_SMC_REG(reg_cur_hammers); + reg_alloc->free_SMC_REG(reg_num_runs); + reg_alloc->free_SMC_REG(reg_cur_runs); +} + +void read_row(Program* prog, SoftMCRegAllocator* reg_alloc, const uint bank_id, const uint row_id){ + + SMC_REG reg_bank_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_num_cols = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_row_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_col_addr = reg_alloc->allocate_SMC_REG(); + + prog->add_inst(SMC_LI(8, CASR)); + prog->add_inst(SMC_LI(NUM_COLS_PER_ROW*8, reg_num_cols)); + prog->add_inst(SMC_LI(bank_id, reg_bank_addr)); + prog->add_inst(SMC_LI(row_id, reg_row_addr)); + + // activate the victim row + add_op_with_delay(*prog, SMC_ACT(reg_bank_addr, 0, reg_row_addr, 0), 0, trcd_cycles - 5); + prog->add_inst(SMC_LI(0, reg_col_addr)); + + // read data from the row and precharge + string new_lbl = createSMCLabel("READ_ROW"); + prog->add_label(new_lbl); + add_op_with_delay(*prog, SMC_READ(reg_bank_addr, 0, reg_col_addr, 1, 0, 0), 0, 0); + prog->add_branch(Program::BR_TYPE::BL, reg_col_addr, reg_num_cols, new_lbl); + + // precharge the open bank + add_op_with_delay(*prog, SMC_PRE(reg_bank_addr, 0, 0), 0, trp_cycles); + + reg_alloc->free_SMC_REG(reg_bank_addr); + reg_alloc->free_SMC_REG(reg_num_cols); + reg_alloc->free_SMC_REG(reg_row_addr); + reg_alloc->free_SMC_REG(reg_col_addr); + +} + +void read_rs(Program* prog, SoftMCRegAllocator* reg_alloc, const RowSet rs){ + for(auto victim_id: rs.victim_ids) + read_row(prog, reg_alloc, rs.bank_id, victim_id); +} + +vector<uint> collect_bitflips(const char* read_data){ + + bitset<512> read_data_bitset; + vector<uint> bitflips; + uint32_t* iread_data = (uint32_t*) read_data; + uint bit_loc; + + // check for bitflips in each cache line + for(int cl = 0; cl < ROW_SIZE/64; cl++) { + read_data_bitset.reset(); + for(int i = 0; i < 512/32; i++) { + bitset<512> tmp_bitset = iread_data[cl*(512/32) + i]; + + read_data_bitset |= (tmp_bitset << i*32); + } + // compare and print errors + bitset<512> error_mask = read_data_bitset ^ vic_data_pattern; + if(error_mask.any()) { + // there is at least one bitflip in this cache line + for(uint i = 0; i < error_mask.size(); i++){ + if(error_mask.test(i)){ + bit_loc = cl*CACHE_LINE_BITS + i; + bitflips.push_back(bit_loc); + } + } + } + } + + return bitflips; +} + +vector<uint> get_bitflips(SoftMCPlatform& platform, const RowSet& rs){ + + vector<uint> num_bitflips; + uint read_data_size = ROW_SIZE*rs.victim_ids.size(); + + char buf[read_data_size*2]; + + platform.receiveData(buf, read_data_size); + for(uint vic_ind = 0; vic_ind < rs.victim_ids.size(); vic_ind++){ + auto bitflips = collect_bitflips(buf + vic_ind*ROW_SIZE); + num_bitflips.push_back(bitflips.size()); + } + return num_bitflips; +} + +vector<uint> run_single_test(SoftMCPlatform& platform, const RowSet rs, + const uint hc_per_run, const uint num_runs, + const uint remaining_hc){ + + Program prog; + SoftMCRegAllocator reg_alloc = SoftMCRegAllocator(NUM_SOFTMC_REGS, reserved_regs); + + init_program(prog); + // INIT DATA + init_rs(&prog, ®_alloc, rs); + + // HAMMER + if(hc_per_run > 0) + hammer_rs(&prog, ®_alloc, rs, hc_per_run, num_runs); + if(remaining_hc > 0) + hammer_rs(&prog, ®_alloc, rs, remaining_hc, 1); + + // READ DATA + read_rs(&prog, ®_alloc, rs); + + // END PROGRAM + end_program(prog); + + #ifdef PRINT_SOFTMC_PROGS + std::cout << "--- SoftMCProg ---" << std::endl; + prog.pretty_print(); // DEBUG + #endif + + // EXECUTE PROGRAM + platform.execute(prog); + + return get_bitflips(platform, rs); +} + +RowSet get_rowset(string rh_pattern, uint bank, uint row){ + RowSet rs; + + rs.bank_id = bank; + for(int i = 0; i < rh_pattern.length(); i++){ + if(rh_pattern.at(i) == 'A') + rs.aggr_ids.push_back(to_physical_row_id(row + i)); + else if(rh_pattern.at(i) == 'V') + rs.victim_ids.push_back(to_physical_row_id(row + i)); + } + + return rs; +} + +int main(int argc, char** argv){ + + //========================Program Options======================== + string rh_pattern = "VAVAV"; + uint target_bank = 1; + uint arg_log_phys_conv_scheme = 0; + uint data_pattern_select = 2; + uint cascade_amount = 1; + uint hc = 1000; + string out_filename = ""; + + if (argc != 5) { + cerr << RED_TXT << "Usage: " << argv[0] << " <hc_per_aggr> <cascade_amount> <data_pattern_select> <out_filename>" << NORMAL_TXT << endl; + return -1; + } + + hc = atoi(argv[1]); + cascade_amount = atoi(argv[2]); + data_pattern_select = atoi(argv[3]); + out_filename = argv[4]; + + //========================Input Checking======================== + if(!(data_pattern_select >= 0 && data_pattern_select < 8)){ + cerr << RED_TXT << "--data_pattern should be between 0 and 8." << NORMAL_TXT << endl; + return -1; + } + //========================Platform Config======================== + SoftMCPlatform platform; + int err; + if((err = platform.init()) != SOFTMC_SUCCESS){ + cerr << "Could not initialize SoftMC Platform: " << err << endl; + return err; + } + platform.reset_fpga(); + platform.set_aref(false); // disable refresh + //========================Out_file Config======================== + std::ofstream out_file; + if(out_filename != ""){ + out_file.open(out_filename); + }else{ + out_file.open("/dev/null"); + } + //========================Parse Inputs======================== + // Logical to physical conversion + logical_physical_conversion_scheme = (LogPhysRowIDScheme) arg_log_phys_conv_scheme; + // Input Row Data + const uint vic_patterns[] = {0x00000000, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x55555555, 0xAAAAAAAA, 0x00000000, 0xFFFFFFFF}; + const uint aggr_patterns[] = {0xFFFFFFFF, 0x00000000, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x00000000, 0xFFFFFFFF}; + for(int i = 0; i < 16; i++){ + vic_data_pattern <<=32; + vic_data_pattern |= vic_patterns[data_pattern_select]; + aggr_data_pattern <<=32; + aggr_data_pattern |= aggr_patterns[data_pattern_select]; + } + //========================Parameter Calculations======================== + uint total_victims = count(rh_pattern.begin(), rh_pattern.end(), 'V'); + uint total_aggrs = count(rh_pattern.begin(), rh_pattern.end(), 'A'); + + uint hc_per_run = (cascade_amount != -1)? cascade_amount: hc; + uint num_runs = (uint) floor(hc/hc_per_run); + uint remaining_hc = hc - hc_per_run*num_runs; + //========================Information======================== + out_file << "RH_pattern: " << rh_pattern << endl + << "HC_per_run: " << hc_per_run << endl + << "Num_runs: " << num_runs << endl + << "Remaining hc: " << remaining_hc << endl + << "Total_hc: " << hc << endl + << "Results" << endl + << "====================" << endl; + //========================Run Analyzer======================== + + + vector<uint> total_bitflips(total_victims, 0); + + + for(uint r = 0; r < NUM_ROWS; r++){ + + RowSet rs = get_rowset(rh_pattern, target_bank, r); + + auto num_bitflips = run_single_test(platform, rs, hc_per_run, num_runs, remaining_hc); + + if(accumulate(num_bitflips.begin(), num_bitflips.end(), 0) > 0){ + out_file << "Row " << r << ": "; + + uint bitflips_ind = 0; + + for(int i = 0; i < rh_pattern.length(); i++){ + if(rh_pattern.at(i) == 'V'){ + out_file << num_bitflips[bitflips_ind] << "-"; + total_bitflips[bitflips_ind] += num_bitflips[bitflips_ind]; + bitflips_ind++; + }else if(rh_pattern.at(i) == 'A'){ + out_file << "A-"; + }else{ + out_file << "_-"; + } + } + out_file << endl; + } + + } + + out_file << "Total bitflips: "; + uint bitflips_ind = 0; + for(int i = 0; i < rh_pattern.length(); i++){ + if(rh_pattern.at(i) == 'V'){ + out_file << total_bitflips[bitflips_ind++] << "-"; + }else if(rh_pattern.at(i) == 'A'){ + out_file << "A-"; + }else{ + out_file << "_-"; + } + } + out_file << endl; + + cout << "The test has finished!" << endl; + + out_file.close(); + + return 0; +}
\ No newline at end of file diff --git a/sources/apps/case_studies/cs1_interleaving_pattern/tools.h b/sources/apps/case_studies/cs1_interleaving_pattern/tools.h new file mode 100644 index 0000000..2c00865 --- /dev/null +++ b/sources/apps/case_studies/cs1_interleaving_pattern/tools.h @@ -0,0 +1,213 @@ +#pragma once +#define TOOLS_H + +#include "instruction.h" +#include "prog.h" + +#include <cstdint> +#include <vector> +#include <exception> +#include <cassert> +#include <algorithm> +#include <chrono> +#include <iostream> + +Inst all_nops() +{ + return __pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); +} + +void sleep_delay (Program& program, uint64_t sleep_time) { + while(sleep_time > UINT32_MAX){ + program.add_inst(SMC_SLEEP(UINT32_MAX)); + sleep_time -= UINT32_MAX; + } + switch(sleep_time){ + case 0: + break; + case 1: + program.add_inst(all_nops()); + break; + case 2: + program.add_inst(all_nops()); + program.add_inst(all_nops()); + break; + default: + program.add_inst(SMC_SLEEP(sleep_time)); + break; + } +} + +int add_op_with_delay (Program& prog, Mininst ins, int before_cycles, int after_cycles) { + + int remaining = before_cycles < 0 ? 0 : before_cycles; + + while(remaining >= 4) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + switch(remaining) { + case 0: + prog.add_inst(__pack_mininsts(ins, SMC_NOP(), SMC_NOP(), SMC_NOP())); + remaining = after_cycles - 3; + break; + case 1: + prog.add_inst(__pack_mininsts(SMC_NOP(), ins, SMC_NOP(), SMC_NOP())); + remaining = after_cycles - 2; + break; + case 2: + prog.add_inst(__pack_mininsts(SMC_NOP(), SMC_NOP(), ins, SMC_NOP())); + remaining = after_cycles - 1; + break; + case 3: + prog.add_inst(__pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), ins)); + remaining = after_cycles; + break; + + default: + assert(false && "This line should not be reached. Possible bug in the program."); + } + + while (remaining >= 4) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + return remaining; +} + +int add_op_with_delay (Program& prog, Inst ins, int before_cycles, int after_cycles) { + + int remaining = before_cycles; + + while(remaining > 0) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + prog.add_inst(ins); + remaining = after_cycles; + + while (remaining >= 4) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + return remaining; +} + + + +typedef uint32_t SMC_REG; + +struct OutOfSoftMCRegsException : public std::exception { + const char * what () const throw () { + return "No more SoftMC registers to allocate."; + } +}; + +static uint32_t label_counter = 0; +std::string createSMCLabel(const std::string& name) { + return name + std::to_string(label_counter++); +} + +class SoftMCRegAllocator { + + public: + SoftMCRegAllocator(uint32_t num_regs, const std::vector<uint32_t>& reserved_regs) { + free_regs.reserve(num_regs); + + for(uint32_t i = 0; i < num_regs; i++) { + if(std::find(reserved_regs.begin(), reserved_regs.end(), i) == reserved_regs.end()) + free_regs.emplace_back(i); + } + } + + SMC_REG allocate_SMC_REG() { + if(free_regs.size() == 0) + throw OutOfSoftMCRegsException(); + + SMC_REG ret_reg = *(free_regs.begin()); + free_regs.erase(free_regs.begin()); + return ret_reg; + } + + void free_SMC_REG(const SMC_REG r) { + // make sure r is not in the free list + auto it = std::find(free_regs.begin(), free_regs.end(), r); + assert(it == free_regs.end()); + + free_regs.push_back(r); + } + + uint num_free_regs() const { + return free_regs.size(); + } + + private: + std::vector<uint32_t> free_regs; +}; + + +typedef uint PhysicalRowID; +typedef uint LogicalRowID; + +typedef enum LogPhysRowIDScheme { + SEQUENTIAL, + SAMSUNG, + MAX +} LogPhysRowIDScheme; + +LogPhysRowIDScheme logical_physical_conversion_scheme = LogPhysRowIDScheme::SEQUENTIAL; + +PhysicalRowID to_physical_row_id(uint logical_row_id) { + + switch(logical_physical_conversion_scheme) { + case LogPhysRowIDScheme::SEQUENTIAL: { + return logical_row_id; + break; + } + case LogPhysRowIDScheme::SAMSUNG: { + if(logical_row_id & 0x8) { + PhysicalRowID phys_row_id = logical_row_id & 0xFFFFFFF9; + phys_row_id |= (~logical_row_id & 0x00000006); // set bit pos 3 and 2 + + return phys_row_id; + } else { + return logical_row_id; + } + break; + } + default: { + std::cout << "ERROR: unimplemented logical to physical row id conversion scheme!" << std::endl; + exit(1); + } + } +} + +LogicalRowID to_logical_row_id(uint physical_row_id) { + switch(logical_physical_conversion_scheme) { + case LogPhysRowIDScheme::SEQUENTIAL: { + return physical_row_id; + break; + } + case LogPhysRowIDScheme::SAMSUNG: { + if(physical_row_id & 0x8) { + PhysicalRowID log_row_id = physical_row_id & 0xFFFFFFF9; + log_row_id |= (~physical_row_id & 0x00000006); // set bit pos 3 and 2 + + return log_row_id; + } else { + return physical_row_id; + } + break; + } + default: { + std::cout << "ERROR: unimplemented physical to logical row id conversion scheme!" << std::endl; + exit(1); + } + } + + return 0; +} diff --git a/sources/apps/case_studies/cs2_data_patterns/Makefile b/sources/apps/case_studies/cs2_data_patterns/Makefile new file mode 100644 index 0000000..953fe34 --- /dev/null +++ b/sources/apps/case_studies/cs2_data_patterns/Makefile @@ -0,0 +1,33 @@ +program_NAME := TEST +program_CXX_SRCS := test.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)) + +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/case_studies/cs2_data_patterns/README.md b/sources/apps/case_studies/cs2_data_patterns/README.md new file mode 100644 index 0000000..e4a94b3 --- /dev/null +++ b/sources/apps/case_studies/cs2_data_patterns/README.md @@ -0,0 +1,11 @@ +## Case Study #2: RowHammer: Data Patterns + +### Instructions + +1. run `make` to compile the DRAM Bender program +2. execute `./TEST <hc_per_aggr> <target_row> <aggr_pattern_select> <vic_pattern_select> <out_filename>` to run the experiment + - hc_per_aggr: Total number of activation per aggressor row. + - target_row: The target row for RH attack. + - aggr_pattern_select: SoftMC for 0x00 to 0xFF patterns, DRAM-Bender for 256 random patterns. + - vic_pattern_select: 0 for all-zeros, 1 for all-ones. + - out_filename: output filename for the results. The output file has the bitflip locations for each victim row and aggr pattern. diff --git a/sources/apps/case_studies/cs2_data_patterns/test.cpp b/sources/apps/case_studies/cs2_data_patterns/test.cpp new file mode 100644 index 0000000..a1a19a0 --- /dev/null +++ b/sources/apps/case_studies/cs2_data_patterns/test.cpp @@ -0,0 +1,561 @@ +#include "instruction.h" +#include "prog.h" +#include "platform.h" +#include "tools.h" + +#include <string> +#include <fstream> +#include <iostream> +#include <list> +#include <cassert> +#include <bitset> +#include <chrono> +#include <iomanip> +#include <math.h> + +#include <array> +#include <algorithm> +#include <numeric> +#include <ctime> + +// #define PRINT_SOFTMC_PROGS + +using namespace std; + +#define CASR 0 +#define BASR 1 +#define RASR 2 + +#define NUM_SOFTMC_REGS 16 +#define FPGA_PERIOD 1.5015f // ns + +#define RED_TXT "\033[31m" +#define GREEN_TXT "\033[32m" +#define YELLOW_TXT "\033[33m" +#define BLUE_TXT "\033[34m" +#define MAGENTA_TXT "\033[35m" +#define NORMAL_TXT "\033[0m" + +int NUM_BANKS = 16; // this is the total number of banks in the chip +int NUM_BANK_GROUPS = 4; +int NUM_ROWS = 32768; +int ROW_SIZE = 8192; +int NUM_COLS_PER_ROW = 128; +int CHIP_NUM = 4; +int CACHE_LINE_BITS = 512; + +float DEFAULT_TRCD = 13.5f; // ns +float DEFAULT_TRAS = 35.0f; // ns +float DEFAULT_TRP = 13.5f; // ns +float DEFAULT_TWR = 15.0f; // ns +float DEFAULT_TRFC = 260.0f; // ns +float DEFAULT_TRRDS = 5.3f; // ns (ACT-ACT to different bank groups) +float DEFAULT_TRRDL = 6.4f; // ns (ACT-ACT to same bank group) +float DEFAULT_TREFI = 7800.0f; + +int trcd_cycles = (int) ceil(DEFAULT_TRCD/FPGA_PERIOD); +int tras_cycles = (int) ceil(DEFAULT_TRAS/FPGA_PERIOD); +int trp_cycles = (int) ceil(DEFAULT_TRP/FPGA_PERIOD); +int twr_cycles = (int) ceil(DEFAULT_TWR/FPGA_PERIOD); +int trfc_cycles = (int) ceil(DEFAULT_TRFC/FPGA_PERIOD); +int trrds_cycles = (int) ceil(DEFAULT_TRRDS/FPGA_PERIOD); +int trrdl_cycles = (int) ceil(DEFAULT_TRRDL/FPGA_PERIOD); +int trefi_cycles = (int) ceil(DEFAULT_TREFI/FPGA_PERIOD); + +vector<uint32_t> reserved_regs{CASR, BASR, RASR}; +vector<uint> special_pattern; + +typedef struct RowSet { + vector<uint> victim_ids; + vector<uint> aggr_ids; + vector<uint> isol_ids; + uint bank_id; +} RowSet; + +void init_program(Program& prog){ + add_op_with_delay(prog, SMC_PRE(0, 0, 1), 0, trp_cycles); // precharge all banks +} + +void end_program(Program& prog){ + prog.add_inst(all_nops()); + prog.add_inst(SMC_END()); +} + +void init_row(Program* prog, SoftMCRegAllocator* reg_alloc, const uint target_bank, const uint target_row, + const bitset<512> pattern){ + + SMC_REG reg_row_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_col_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_bank_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_num_cols = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_wrdata = reg_alloc->allocate_SMC_REG(); + + bitset<512> bitset_int_mask(0xFFFFFFFF); + + prog->add_inst(SMC_LI(NUM_COLS_PER_ROW*8, reg_num_cols)); + prog->add_inst(SMC_LI(target_bank, reg_bank_addr)); + prog->add_inst(SMC_LI(target_row, reg_row_addr)); + prog->add_inst(SMC_LI(8, CASR)); + + // set up the input data in the wide register + for(int pos = 0; pos < 16; pos++){ + prog->add_inst(SMC_LI((((pattern >> 32*pos) & bitset_int_mask).to_ulong() & 0xFFFFFFFF), reg_wrdata)); + prog->add_inst(SMC_LDWD(reg_wrdata, pos)); + } + + // activate the target row + uint remaining = add_op_with_delay(*prog, SMC_ACT(reg_bank_addr, 0, reg_row_addr, 0), 0, trcd_cycles - 5); + + // write data to the row and precharge + prog->add_inst(SMC_LI(0, reg_col_addr)); + + string new_lbl = createSMCLabel("INIT_ROW"); + prog->add_label(new_lbl); + add_op_with_delay(*prog, SMC_WRITE(reg_bank_addr, 0, reg_col_addr, 1, 0, 0), 0, 0); + prog->add_branch(Program::BR_TYPE::BL, reg_col_addr, reg_num_cols, new_lbl); + + // precharge the open bank + add_op_with_delay(*prog, SMC_PRE(reg_bank_addr, 0, 0), 0, trp_cycles); + + reg_alloc->free_SMC_REG(reg_row_addr); + reg_alloc->free_SMC_REG(reg_col_addr); + reg_alloc->free_SMC_REG(reg_wrdata); + reg_alloc->free_SMC_REG(reg_bank_addr); + reg_alloc->free_SMC_REG(reg_num_cols); + +} + +void init_rs(Program* prog, SoftMCRegAllocator* reg_alloc, const RowSet rs, + const bitset<512> vic_pattern, const bitset<512> aggr_pattern) { + //init aggrs + for(auto aggr_id: rs.aggr_ids) + init_row(prog, reg_alloc, rs.bank_id, aggr_id, aggr_pattern); + //init victims + for(auto victim_id: rs.victim_ids) + init_row(prog, reg_alloc, rs.bank_id, victim_id, vic_pattern); +} + +void hammer_rs(Program* prog, SoftMCRegAllocator* reg_alloc, const RowSet rs, + const uint hc){ + + SMC_REG reg_bank_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_row_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_num_hammers = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_cur_hammers = reg_alloc->allocate_SMC_REG(); + + prog->add_inst(SMC_LI(rs.bank_id, reg_bank_addr)); + prog->add_inst(SMC_LI(hc, reg_num_hammers)); + prog->add_inst(SMC_LI(0, reg_cur_hammers)); + + string lbl_rh = createSMCLabel("ROWHAMMERING"); + prog->add_label(lbl_rh); + for(auto aggr_id: rs.aggr_ids){ + prog->add_inst(SMC_LI(aggr_id, reg_row_addr)); + + uint remaining_cycs = add_op_with_delay(*prog, SMC_ACT(reg_bank_addr, 0, reg_row_addr, 0), 0, tras_cycles - 1); + remaining_cycs = add_op_with_delay(*prog, SMC_PRE(reg_bank_addr, 0, 0), remaining_cycs, trp_cycles - 25); + } + prog->add_inst(SMC_ADDI(reg_cur_hammers, 1, reg_cur_hammers)); + prog->add_branch(Program::BR_TYPE::BL, reg_cur_hammers, reg_num_hammers, lbl_rh); + + reg_alloc->free_SMC_REG(reg_bank_addr); + reg_alloc->free_SMC_REG(reg_row_addr); + reg_alloc->free_SMC_REG(reg_num_hammers); + reg_alloc->free_SMC_REG(reg_cur_hammers); +} + +void read_row(Program* prog, SoftMCRegAllocator* reg_alloc, const uint bank_id, const uint row_id){ + + SMC_REG reg_bank_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_num_cols = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_row_addr = reg_alloc->allocate_SMC_REG(); + SMC_REG reg_col_addr = reg_alloc->allocate_SMC_REG(); + + prog->add_inst(SMC_LI(8, CASR)); + prog->add_inst(SMC_LI(NUM_COLS_PER_ROW*8, reg_num_cols)); + prog->add_inst(SMC_LI(bank_id, reg_bank_addr)); + prog->add_inst(SMC_LI(row_id, reg_row_addr)); + + // activate the victim row + add_op_with_delay(*prog, SMC_ACT(reg_bank_addr, 0, reg_row_addr, 0), 0, trcd_cycles - 5); + prog->add_inst(SMC_LI(0, reg_col_addr)); + + // read data from the row and precharge + string new_lbl = createSMCLabel("READ_ROW"); + prog->add_label(new_lbl); + add_op_with_delay(*prog, SMC_READ(reg_bank_addr, 0, reg_col_addr, 1, 0, 0), 0, 0); + prog->add_branch(Program::BR_TYPE::BL, reg_col_addr, reg_num_cols, new_lbl); + + // precharge the open bank + add_op_with_delay(*prog, SMC_PRE(reg_bank_addr, 0, 0), 0, trp_cycles); + + reg_alloc->free_SMC_REG(reg_bank_addr); + reg_alloc->free_SMC_REG(reg_num_cols); + reg_alloc->free_SMC_REG(reg_row_addr); + reg_alloc->free_SMC_REG(reg_col_addr); + +} + +void read_rs(Program* prog, SoftMCRegAllocator* reg_alloc, const RowSet rs){ + for(auto victim_id: rs.victim_ids) + read_row(prog, reg_alloc, rs.bank_id, victim_id); +} + +vector<uint> collect_bitflips(const char* read_data, + const bitset<512> vic_pattern){ + + bitset<512> read_data_bitset; + vector<uint> bitflips; + uint32_t* iread_data = (uint32_t*) read_data; + uint bit_loc; + + // check for bitflips in each cache line + for(int cl = 0; cl < ROW_SIZE/64; cl++) { + read_data_bitset.reset(); + for(int i = 0; i < 512/32; i++) { + bitset<512> tmp_bitset = iread_data[cl*(512/32) + i]; + + read_data_bitset |= (tmp_bitset << i*32); + } + // compare and print errors + bitset<512> error_mask = read_data_bitset ^ vic_pattern; + if(error_mask.any()){ + // there is at least one bitflip in this cache line + for(uint i = 0; i < error_mask.size(); i++){ + if(error_mask.test(i)){ + bit_loc = cl*CACHE_LINE_BITS + i; + bitflips.push_back(bit_loc); + } + } + } + } + + return bitflips; +} + +vector<vector<uint>> get_bitflips(SoftMCPlatform& platform, const RowSet& rs, + const bitset<512> vic_pattern){ + + vector<vector<uint>> loc_bitflips; + uint read_data_size = ROW_SIZE*rs.victim_ids.size(); + + char buf[read_data_size*2]; + + platform.receiveData(buf, read_data_size); + for(uint vic_ind = 0; vic_ind < rs.victim_ids.size(); vic_ind++){ + auto bitflips = collect_bitflips(buf + vic_ind*ROW_SIZE, vic_pattern); + loc_bitflips.push_back(bitflips); + } + return loc_bitflips; +} + +vector<vector<uint>> run_single_test(SoftMCPlatform& platform, const RowSet rs, const uint hc, + const bitset<512> vic_pattern, const bitset<512> aggr_pattern){ + + Program prog; + SoftMCRegAllocator reg_alloc = SoftMCRegAllocator(NUM_SOFTMC_REGS, reserved_regs); + + init_program(prog); + // INIT DATA + init_rs(&prog, ®_alloc, rs, vic_pattern, aggr_pattern); + + // HAMMER + hammer_rs(&prog, ®_alloc, rs, hc); + + // READ DATA + read_rs(&prog, ®_alloc, rs); + + // END PROGRAM + end_program(prog); + + #ifdef PRINT_SOFTMC_PROGS + std::cout << "--- SoftMCProg ---" << std::endl; + prog.pretty_print(); // DEBUG + #endif + + // EXECUTE PROGRAM + platform.execute(prog); + + return get_bitflips(platform, rs, vic_pattern); +} + +RowSet get_rowset(string rh_pattern, uint bank, uint row){ + RowSet rs; + + rs.bank_id = bank; + for(int i = 0; i < rh_pattern.length(); i++){ + if(rh_pattern.at(i) == 'A') + rs.aggr_ids.push_back(to_physical_row_id(row + i)); + else if(rh_pattern.at(i) == 'V') + rs.victim_ids.push_back(to_physical_row_id(row + i)); + else if(rh_pattern.at(i) == 'I') + rs.isol_ids.push_back(to_physical_row_id(row + i)); + } + + return rs; +} + +vector<vector<bitset<512>>> parse_data_patterns(const uint aggr_pattern_select, const uint vic_pattern_select, const uint isol_pattern_select, + const vector<uint> spec_data_patterns){ + + vector<bitset<512>> aggr_patterns, vic_patterns, isol_patterns; + bitset<512> aggr_set; + aggr_set.reset(); + switch (aggr_pattern_select){ + case 0: + aggr_patterns.push_back(aggr_set); + break; + case 1: + aggr_set.set(); + aggr_patterns.push_back(aggr_set); + break; + case 2: + for(uint b = 0; b < 64; b++){ + aggr_set |= 0x55; + aggr_set <<= 8; + } + aggr_patterns.push_back(aggr_set); + break; + case 3: + for(uint b = 0; b < 64; b++){ + aggr_set |= 0xAA; + aggr_set <<= 8; + } + aggr_patterns.push_back(aggr_set); + break; + case 8: + for(uint b = 0; b < 64; b++){ + aggr_set |= 0x0F; + aggr_set <<= 8; + } + aggr_patterns.push_back(aggr_set); + break; + case 9: + for(uint b = 0; b < 64; b++){ + aggr_set |= 0xF0; + aggr_set <<= 8; + } + aggr_patterns.push_back(aggr_set); + break; + case 4: + for(uint p = 0; p < 256; p++){ + aggr_set.reset(); + for(uint b = 0; b < 64; b++){ + aggr_set |= p; + aggr_set <<= 8; + } + aggr_patterns.push_back(aggr_set); + } + break; + case 6: + for(auto p: spec_data_patterns){ + aggr_set.reset(); + for(uint b = 0; b < 64; b++){ + aggr_set |= p; + aggr_set <<= 8; + } + aggr_patterns.push_back(aggr_set); + } + break; + case 7: + for(uint b = 0; b < 64; b++){ + aggr_set |= spec_data_patterns[b]; + aggr_set <<= 8; + } + aggr_patterns.push_back(aggr_set); + break; + } + + bitset<512> vic_set; + vic_set.reset(); + switch (vic_pattern_select){ + case 0: + vic_patterns.push_back(vic_set); + break; + case 1: + vic_set.set(); + vic_patterns.push_back(vic_set); + break; + case 2: + for(uint b = 0; b < 64; b++){ + vic_set |= 0x55; + vic_set <<= 8; + } + vic_patterns.push_back(vic_set); + break; + case 3: + for(uint b = 0; b < 64; b++){ + vic_set |= 0xAA; + vic_set <<= 8; + } + vic_patterns.push_back(vic_set); + break; + case 8: + for(uint b = 0; b < 64; b++){ + vic_set |= 0x0F; + vic_set <<= 8; + } + vic_patterns.push_back(vic_set); + break; + case 9: + for(uint b = 0; b < 64; b++){ + vic_set |= 0xF0; + vic_set <<= 8; + } + vic_patterns.push_back(vic_set); + break; + case 5: + vic_patterns.push_back(vic_set); + break; + } + + bitset<512> isol_set; + isol_set.reset(); + switch (isol_pattern_select){ + case 0: + isol_patterns.push_back(isol_set); + break; + case 1: + isol_set.set(); + isol_patterns.push_back(isol_set); + break; + case 2: + for(uint b = 0; b < 64; b++){ + isol_set |= 0x55; + isol_set <<= 8; + } + isol_patterns.push_back(isol_set); + break; + case 3: + for(uint b = 0; b < 64; b++){ + isol_set |= 0xAA; + isol_set <<= 8; + } + isol_patterns.push_back(isol_set); + break; + case 8: + for(uint b = 0; b < 64; b++){ + isol_set |= 0x0F; + isol_set <<= 8; + } + isol_patterns.push_back(isol_set); + break; + case 9: + for(uint b = 0; b < 64; b++){ + isol_set |= 0xF0; + isol_set <<= 8; + } + isol_patterns.push_back(isol_set); + break; + } + + vector<vector<bitset<512>>> patterns; + patterns.push_back(aggr_patterns); + patterns.push_back(vic_patterns); + patterns.push_back(isol_patterns); + + return patterns; +} + +int main(int argc, char** argv){ + + //========================Program Options======================== + string out_filename = ""; + string rh_pattern = "AVA"; + uint target_bank = 0; + uint target_row = 0; + string aggr_pattern_select = "SoftMC"; + uint vic_pattern_select = 0; + uint arg_log_phys_conv_scheme = 0; + uint hc = 1000; + + if(argc != 6){ + cerr << RED_TXT << "Usage: " << argv[0] << " <hc_per_aggr> <target_row> <aggr_pattern_select> <vic_pattern_select> <out_filename>" << NORMAL_TXT << endl; + return -1; + } + + hc = atoi(argv[1]); + target_row = atoi(argv[2]); + aggr_pattern_select = argv[3]; + vic_pattern_select = atoi(argv[4]); + out_filename = argv[5]; + + //========================Input Checking======================== + if(arg_log_phys_conv_scheme >= LogPhysRowIDScheme::MAX){ + cerr << RED_TXT << "No logical to physical conversion scheme found." << NORMAL_TXT << endl; + return -1; + } + //========================Platform Config======================== + SoftMCPlatform platform; + int err; + if((err = platform.init()) != SOFTMC_SUCCESS){ + cerr << "Could not initialize SoftMC Platform: " << err << endl; + return err; + } + platform.reset_fpga(); + platform.set_aref(false); // disable refresh + //========================Out_file Config======================== + std::ofstream out_file; + if(out_filename != ""){ + out_file.open(out_filename); + }else{ + out_file.open("/dev/null"); + } + //========================Parse Inputs======================== + // Logical to physical conversion + logical_physical_conversion_scheme = (LogPhysRowIDScheme) arg_log_phys_conv_scheme; + //========================Parameter Calculations======================== + uint total_victims = count(rh_pattern.begin(), rh_pattern.end(), 'V'); + uint total_aggrs = count(rh_pattern.begin(), rh_pattern.end(), 'A'); + //========================INFO MSG======================== + std::cout << "RH_pattern: " << rh_pattern << endl + << "Hammer Count: " << hc << endl + << "Target Bank: " << target_bank << endl + << "Target Row: " << target_row << endl + << "Aggressor Data Pattern: " << aggr_pattern_select << endl + << "Victim Data Pattern: " << vic_pattern_select << endl; + //========================Run Analyzer======================== + + RowSet rs = get_rowset(rh_pattern, target_bank, target_row); + bitset<512> aggr_pattern, vic_pattern; + for(uint pattern_id = 0; pattern_id < 256; pattern_id++){ + + string ap_str; + if(aggr_pattern_select == "SoftMC"){ + bitset<8> ap_set(pattern_id); + ap_str = ap_set.to_string(); + }else if(aggr_pattern_select == "DRAM-Bender"){ + bitset<512> ap_set; + for(uint b = 0; b < 512; b++){ + ap_set[b] = rand() % 2; + } + ap_str = "RAND_" + to_string(pattern_id); + } + + if(vic_pattern_select == 0){ + vic_pattern.reset(); + } else if(vic_pattern_select == 1){ + vic_pattern.set(); + } + + auto loc_bitflips = run_single_test(platform, rs, hc, vic_pattern, aggr_pattern); + + uint vic_ind = 0; + + for(auto victim_id: rs.victim_ids){ + out_file << "Victim " << to_logical_row_id(victim_id) << " - Aggr Pat " + << ap_str << ": " << loc_bitflips[vic_ind].size() << " : "; + for(auto bit_loc: loc_bitflips[vic_ind]){ + out_file << bit_loc << ","; + } + vic_ind++; + } + out_file << endl; + + } + + std::cout << "The test has finished!" << endl; + + out_file.close(); + return 0; +}
\ No newline at end of file diff --git a/sources/apps/case_studies/cs2_data_patterns/tools.h b/sources/apps/case_studies/cs2_data_patterns/tools.h new file mode 100644 index 0000000..2c00865 --- /dev/null +++ b/sources/apps/case_studies/cs2_data_patterns/tools.h @@ -0,0 +1,213 @@ +#pragma once +#define TOOLS_H + +#include "instruction.h" +#include "prog.h" + +#include <cstdint> +#include <vector> +#include <exception> +#include <cassert> +#include <algorithm> +#include <chrono> +#include <iostream> + +Inst all_nops() +{ + return __pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); +} + +void sleep_delay (Program& program, uint64_t sleep_time) { + while(sleep_time > UINT32_MAX){ + program.add_inst(SMC_SLEEP(UINT32_MAX)); + sleep_time -= UINT32_MAX; + } + switch(sleep_time){ + case 0: + break; + case 1: + program.add_inst(all_nops()); + break; + case 2: + program.add_inst(all_nops()); + program.add_inst(all_nops()); + break; + default: + program.add_inst(SMC_SLEEP(sleep_time)); + break; + } +} + +int add_op_with_delay (Program& prog, Mininst ins, int before_cycles, int after_cycles) { + + int remaining = before_cycles < 0 ? 0 : before_cycles; + + while(remaining >= 4) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + switch(remaining) { + case 0: + prog.add_inst(__pack_mininsts(ins, SMC_NOP(), SMC_NOP(), SMC_NOP())); + remaining = after_cycles - 3; + break; + case 1: + prog.add_inst(__pack_mininsts(SMC_NOP(), ins, SMC_NOP(), SMC_NOP())); + remaining = after_cycles - 2; + break; + case 2: + prog.add_inst(__pack_mininsts(SMC_NOP(), SMC_NOP(), ins, SMC_NOP())); + remaining = after_cycles - 1; + break; + case 3: + prog.add_inst(__pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), ins)); + remaining = after_cycles; + break; + + default: + assert(false && "This line should not be reached. Possible bug in the program."); + } + + while (remaining >= 4) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + return remaining; +} + +int add_op_with_delay (Program& prog, Inst ins, int before_cycles, int after_cycles) { + + int remaining = before_cycles; + + while(remaining > 0) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + prog.add_inst(ins); + remaining = after_cycles; + + while (remaining >= 4) { + prog.add_inst(all_nops()); + remaining -= 4; + } + + return remaining; +} + + + +typedef uint32_t SMC_REG; + +struct OutOfSoftMCRegsException : public std::exception { + const char * what () const throw () { + return "No more SoftMC registers to allocate."; + } +}; + +static uint32_t label_counter = 0; +std::string createSMCLabel(const std::string& name) { + return name + std::to_string(label_counter++); +} + +class SoftMCRegAllocator { + + public: + SoftMCRegAllocator(uint32_t num_regs, const std::vector<uint32_t>& reserved_regs) { + free_regs.reserve(num_regs); + + for(uint32_t i = 0; i < num_regs; i++) { + if(std::find(reserved_regs.begin(), reserved_regs.end(), i) == reserved_regs.end()) + free_regs.emplace_back(i); + } + } + + SMC_REG allocate_SMC_REG() { + if(free_regs.size() == 0) + throw OutOfSoftMCRegsException(); + + SMC_REG ret_reg = *(free_regs.begin()); + free_regs.erase(free_regs.begin()); + return ret_reg; + } + + void free_SMC_REG(const SMC_REG r) { + // make sure r is not in the free list + auto it = std::find(free_regs.begin(), free_regs.end(), r); + assert(it == free_regs.end()); + + free_regs.push_back(r); + } + + uint num_free_regs() const { + return free_regs.size(); + } + + private: + std::vector<uint32_t> free_regs; +}; + + +typedef uint PhysicalRowID; +typedef uint LogicalRowID; + +typedef enum LogPhysRowIDScheme { + SEQUENTIAL, + SAMSUNG, + MAX +} LogPhysRowIDScheme; + +LogPhysRowIDScheme logical_physical_conversion_scheme = LogPhysRowIDScheme::SEQUENTIAL; + +PhysicalRowID to_physical_row_id(uint logical_row_id) { + + switch(logical_physical_conversion_scheme) { + case LogPhysRowIDScheme::SEQUENTIAL: { + return logical_row_id; + break; + } + case LogPhysRowIDScheme::SAMSUNG: { + if(logical_row_id & 0x8) { + PhysicalRowID phys_row_id = logical_row_id & 0xFFFFFFF9; + phys_row_id |= (~logical_row_id & 0x00000006); // set bit pos 3 and 2 + + return phys_row_id; + } else { + return logical_row_id; + } + break; + } + default: { + std::cout << "ERROR: unimplemented logical to physical row id conversion scheme!" << std::endl; + exit(1); + } + } +} + +LogicalRowID to_logical_row_id(uint physical_row_id) { + switch(logical_physical_conversion_scheme) { + case LogPhysRowIDScheme::SEQUENTIAL: { + return physical_row_id; + break; + } + case LogPhysRowIDScheme::SAMSUNG: { + if(physical_row_id & 0x8) { + PhysicalRowID log_row_id = physical_row_id & 0xFFFFFFF9; + log_row_id |= (~physical_row_id & 0x00000006); // set bit pos 3 and 2 + + return log_row_id; + } else { + return physical_row_id; + } + break; + } + default: { + std::cout << "ERROR: unimplemented physical to logical row id conversion scheme!" << std::endl; + exit(1); + } + } + + return 0; +} diff --git a/sources/apps/case_studies/cs3_bitwise/Makefile b/sources/apps/case_studies/cs3_bitwise/Makefile new file mode 100644 index 0000000..953fe34 --- /dev/null +++ b/sources/apps/case_studies/cs3_bitwise/Makefile @@ -0,0 +1,33 @@ +program_NAME := TEST +program_CXX_SRCS := test.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)) + +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/case_studies/cs3_bitwise/README.md b/sources/apps/case_studies/cs3_bitwise/README.md new file mode 100644 index 0000000..1db9c54 --- /dev/null +++ b/sources/apps/case_studies/cs3_bitwise/README.md @@ -0,0 +1,23 @@ +## Case Study #3: In-DRAM Bitwise Operations + +### Instructions + +1. run `make` to compile the DRAM Bender program +2. execute `run_tests.sh` to generate data under `results` directory + +### Data format + +`run_tests.sh` creates one result file for each iteration of an AND and an OR experiment. For example, `AND-log1.csv` contains the results for the first iteration of an AND experiment. + +A line in this file corresponds to a tested DRAM segment and contains the following comma separated information (taken from test.cpp, line 299): + +``` +row: The address of the first row in the tested segment +op_type: "AND" or "OR" +dp1: Value stored in the first operand +dp2: Value stored in the second operand +t1: Distance between the first ACT and the first PRE command +t2: Distance between the first PRE and the second ACT command +platext: Placement of the operands (see lines 244-264 in test.cpp) +errors: Number of bit errors in the output +```
\ No newline at end of file diff --git a/sources/apps/case_studies/cs3_bitwise/run_tests.sh b/sources/apps/case_studies/cs3_bitwise/run_tests.sh new file mode 100644 index 0000000..21c8fb5 --- /dev/null +++ b/sources/apps/case_studies/cs3_bitwise/run_tests.sh @@ -0,0 +1,12 @@ +#!/bin/bash +mkdir -p results + +for i in {1..10} +do + sudo ./TEST 1 "results/AND-log$i.csv" > /dev/null +done + +for i in {1..10} +do + sudo ./TEST 0 "results/OR-log$i.csv" > /dev/null +done diff --git a/sources/apps/case_studies/cs3_bitwise/test.cpp b/sources/apps/case_studies/cs3_bitwise/test.cpp new file mode 100644 index 0000000..2b71f66 --- /dev/null +++ b/sources/apps/case_studies/cs3_bitwise/test.cpp @@ -0,0 +1,309 @@ +#include "instruction.h" +#include "prog.h" +#include "platform.h" +#include <fstream> +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <cstring> +#include <list> +#include <bitset> + +using namespace std; + +#define buffer_size 8192*8 + +#define NUM_BANKS 1 //16 +#define NUM_ROWS (1024*32) + +// Stride register ids are fixed and should not be changed +// CASR should always be reg 0 +#define CASR 0 +// BASR should always be reg 1 +#define BASR 1 +// RASR should always be reg 2 +#define RASR 2 + +#define CONSTANT 8 +#define OP1 12 +#define OP2 13 + +#define BAR 3 +#define CAR 4 +#define RAR 5 +#define SRC 6 +#define DST 7 + +#define INIT_LOOP 9 + +#define TEMP1 10 +#define NUM_ROWS_REG 11 + + +/** + * @return an instruction formed by NOPs + */ +Inst all_nops() +{ + return __pack_mininsts(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); +} + +SoftMCPlatform platform; + +/** + * To send an ACT -> SLEEP t1 -> PRE -> SLEEP t2 -> ACT sequence + * This seq. will use BAR RAR1 and RAR2 registers + */ +Program genActPreActSequence(int t1, int t2, int row1_reg, int row2_reg, int bank_reg) +{ + Program ret; + // t1 -> ACT to PRE, t2 -> PRE to 2nd ACT + int sz = 3 + t1 + t2; + sz = (4-(sz%4)) + sz; + Mininst buff[sz]; + for(int i = 0 ; i < sz ; i++) + buff[i] = SMC_NOP(); + + // Overwrite with the actual sequence + buff[0] = SMC_ACT(bank_reg, 0, row1_reg, 0); + buff[1+t1] = SMC_PRE(bank_reg, 0, 0); + buff[2+t1+t2] = SMC_ACT(bank_reg, 0, row2_reg, 0); + + for(int i = 0 ; i < sz ; i+=4) + ret.add_inst(buff[i], buff[i+1], buff[i+2], buff[i+3]); + + return ret; +} + +Program genReadRange(int row_reg, int no_rows, int bank_reg) +{ + Program ret; + ret.add_inst(SMC_LI(no_rows, INIT_LOOP)); + ret.add_inst(SMC_ADD(INIT_LOOP, row_reg, INIT_LOOP)); // read until this row + ret.add_label("genReadRange:LOOP_BEGIN"); + ret.add_inst(SMC_LI(0, CAR)); + ret.add_inst(SMC_ACT(bank_reg, 0, row_reg, no_rows>1), SMC_NOP(), SMC_NOP(), SMC_NOP()); + ret.add_inst(SMC_SLEEP(4)); + for(int i = 0 ; i < 128 ; i++) + { + ret.add_inst(SMC_READ(bank_reg, 0, CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); + ret.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + } + ret.add_inst(SMC_SLEEP(4)); + ret.add_inst(SMC_PRE(bank_reg, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); + ret.add_branch(ret.BR_TYPE::BL, row_reg, INIT_LOOP, "genReadRange:LOOP_BEGIN"); + /* + ret.add_inst(SMC_SLEEP(5)); + ret.dump_registers(); + ret.add_inst(SMC_END()); + */ + ret.add_inst(SMC_SUBI(row_reg, no_rows, row_reg)); + return ret; +} + +Program writeRowSlow(unsigned int _BAR, unsigned int _RAR, unsigned int _CAR, unsigned int _PATTERN_REG, unsigned int _TEMP1, string label) +{ + Program prog; + + for (int i = 0 ; i < 16 ; i++) + prog.add_inst(SMC_LDWD(_PATTERN_REG, i)); + + prog.add_inst(SMC_LI(1024, TEMP1)); + + prog.add_inst(SMC_LI(0, _CAR)); + prog.add_inst(SMC_ACT(_BAR, 0, _RAR, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_label("WRS:BEGIN" + label); + prog.add_inst(SMC_WRITE(_BAR, 0, _CAR, 1, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_branch(prog.BR_TYPE::BL, _CAR, TEMP1, "WRS:BEGIN" + label); + prog.add_inst(SMC_PRE(_BAR, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_SLEEP(3)); + + return prog; +} + +Program AMBITTest(bool andOp, unsigned int op1, unsigned int op2, unsigned int t1, unsigned int t2, int op1Placement, int op2Placement, int constantPlacement) +{ + Program prog; + + prog.add_inst(SMC_LI(8, CASR)); + prog.add_inst(SMC_LI(0, BASR)); + prog.add_inst(SMC_LI(1, RASR)); + prog.add_inst(SMC_LI(1, BAR)); + prog.add_inst(SMC_LI(0, RAR)); + prog.add_inst(SMC_LI(NUM_ROWS, NUM_ROWS_REG)); + prog.add_label("SEGMENT_BEGIN"); + for(int i = 0 ; i < 4 ; i++) + { + if(i == op1Placement) + { + prog.add_inst(SMC_LI(op1, OP1)); + prog.add_below(writeRowSlow(BAR, RAR, CAR, OP1, TEMP1, "one")); + } + else if (i == op2Placement) + { + prog.add_inst(SMC_LI(op2, OP2)); + prog.add_below(writeRowSlow(BAR, RAR, CAR, OP2, TEMP1, "two")); + } + else if (i == constantPlacement) + { + prog.add_inst(SMC_LI(andOp ? 0x00000000 : 0xffffffff, CONSTANT)); + prog.add_below(writeRowSlow(BAR, RAR, CAR, CONSTANT, TEMP1, "three")); + } + else + { + prog.add_inst(SMC_LI(0x00000000, CONSTANT)); + prog.add_below(writeRowSlow(BAR, RAR, CAR, CONSTANT, TEMP1, "four")); + } + prog.add_inst(SMC_ADDI(RAR, 1, RAR)); + } + + prog.add_inst(SMC_SUBI(RAR, 3, SRC)); + prog.add_inst(SMC_SUBI(RAR, 2, DST)); + prog.add_below(genActPreActSequence(t1, t2, SRC, DST, BAR)); + + prog.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + prog.add_inst(SMC_PRE(BAR, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); + + //prog.dump_registers(); + + prog.add_below(genReadRange(SRC, 3, BAR)); + prog.add_branch(prog.BR_TYPE::BL, RAR, NUM_ROWS_REG, "SEGMENT_BEGIN"); + prog.add_inst(SMC_END()); + + return prog; +} + +int main(int argc, char * argv[]) +{ + if(platform.init() != SOFTMC_SUCCESS){ + cerr << "Could not initialize SoftMC Platform" << endl; + } + + platform.reset_fpga(); + + if (argc != 3) + { + cout << "Give me two arguments" << endl; + exit(0); + } + bool andOp = false; + + if (atoi(argv[1])) + andOp = true; + else + andOp = false; + + srand(time(NULL)); + + ofstream fileOutput; + fileOutput.open(argv[2]); + fileOutput << "row,operation,op1,op2,t1,t2,op1-placement,op2-placement,constant-placement,bit-flips" << endl; + + for(int i_data = 0 ; i_data < 4 ; i_data++) + { + unsigned int dp1; + unsigned int dp2; + + if (i_data == 0) + { + dp1 = 0x00000000; + dp2 = 0x00000000; + } + else if (i_data == 1) + { + dp1 = 0x00000000; + dp2 = 0xffffffff; + } + else if (i_data == 2) + { + dp1 = 0xffffffff; + dp2 = 0x00000000; + } + else if (i_data == 3) + { + dp1 = 0xffffffff; + dp2 = 0xffffffff; + } + + unsigned int expected = andOp ? (dp1 & dp2) : (dp1 | dp2); + + for (int t1 = 0 ; t1 < 10 ; t1++) + { + for (int t2 = 0 ; t2 < 10 ; t2++) + { + for (int pla = 0 ; pla < 3 ; pla++) + { + string platext; + if (pla == 0) + { + cout << "Begin with " << (andOp ? "AND" : "OR") << " T1:" << t1 << " T2:" << t2 << " OP1:" << 0 << " OP2:" << 1 << " C:" << 2 << endl; + Program prog = AMBITTest(andOp, dp1, dp2, t1, t2, 0, 1, 2); + platext = "0,1,2"; + platform.execute(prog); + } + else if (pla == 1) + { + cout << "Begin with T1:" << t1 << " T2:" << t2 << " OP1:" << 0 << " OP2:" << 2 << " C:" << 1 << endl; + Program prog = AMBITTest(andOp, dp1, dp2, t1, t2, 0, 2, 1); + platext = "0,2,1"; + platform.execute(prog); + } + else if (pla == 2) + { + cout << "Begin with T1:" << t1 << " T2:" << t2 << " OP1:" << 1 << " OP2:" << 2 << " C:" << 0 << endl; + Program prog = AMBITTest(andOp, dp1, dp2, t1, t2, 1, 2, 0); + platext = "1,2,0"; + platform.execute(prog); + } + + //platform.readRegisterDump(); + //exit(0); + + for (int row = 0 ; row < NUM_ROWS ; row += 4) + { + uint8_t rd_rows[3][8192]; + + for(int i = 0 ; i < 3 ; i++) // Read three rows each main iteration + platform.receiveData((void*)rd_rows[i], 8192); + + uint32_t* readData1 = ((uint32_t*) rd_rows[0]); + uint32_t* readData2 = ((uint32_t*) rd_rows[1]); + uint32_t* readData3 = ((uint32_t*) rd_rows[2]); + unsigned long long errors = 0; + bool noTRA = false; + for(int i = 0 ; i < 8192/4 ; i++) + { + unsigned int differences; + if (readData1[i] == readData2[i] && readData2[i] == readData3[i]) + differences = __builtin_popcount(readData1[i]^expected); + else{ // if !TRA, assume errors + noTRA = true; + break; + } + errors += differences; + } + if(noTRA) + { + fileOutput << row << "," << (andOp ? "AND" : "OR") << "," << dp1 << "," << dp2 << "," << t1 << "," << t2 << "," << platext << "," << -1 << endl; + cout << "Row:" << row << " No TRA " << endl; + } + else + { + fileOutput << row << "," << (andOp ? "AND" : "OR") << "," << dp1 << "," << dp2 << "," << t1 << "," << t2 << "," << platext << "," << errors << endl; + cout << "Row:" << row << " Errors:" << errors << endl; + } + } + } + } + } + } + fileOutput.close(); + printf("\nTest Finished\n"); +} |
