Hello we are trying to figure out how to use the dram bender tutorial from the youtube video and are running into an issue with the number of bit flips being very high than expected? we have even tried to print the values of the rows and still are seeing a data pattern miss match. WOuld someone be able to take a look at our solution and maybe see what could be wrong.
int hammer_count = atoi(argv[1]); // arguement the program takes from the command line aka when you do .ps 10 10 is the hammer count which indicates the number of times the row will be activated
SoftMCPlatform platform; //sends and recieves info from the board
platform.init();
platform.reset_fpga(); // sets a reset signal to the fpga we send it everytime to get the state to a meaningful start
Program p; //program object
const int ROW_ADDRESS_R = 3;
const int BANK_ADDRESS_R = 4;
const int COLUMN_ADDRESS_R = 5;
p.add_inst(SMC_LI(99,ROW_ADDRESS_R)); //load immediate which initializes a register with an immeidiate value aka 999 which goes to rowaddress 3
p.add_inst(SMC_LI(0, BANK_ADDRESS_R));
p.add_inst(SMC_LI(0, COLUMN_ADDRESS_R));
const int DATA_PATTERN_R = 6; // dram data register to initialize rows with data 32 bit x 32 bit but with one insruction we can only modify 32 bits at a time
const int DATA_PATTERN_INV_R = 7;
p.add_inst(SMC_LI(0xFFFFFFFF, DATA_PATTERN_R));
p.add_inst(SMC_LI(0x00000000, DATA_PATTERN_INV_R));
for (int i = 0; i < 16; i++) // this loop takes into account the 32 x 32 bit since the register is 512 bit wide 16 of these 32 bits which takes the the register identifier and loads with i aka the offset to initalize all of the rows
p.add_inst(SMC_LDWD(DATA_PATTERN_INV_R, i));
p.add_inst(SMC_PRE(BANK_ADDRESS_R, 0, 1), SMC_NOP(), SMC_NOP(), SMC_NOP()); // this just makes sure that all of the banks are precharged reason to do this is is because the rows might be in an undifined state which is why we want to minimize that error
p.add_inst(SMC_SLEEP(10));// one dram command can execute 4 dram commands || what sleep does is does no operations for that number of fpga clock cycles aka 10
//Write to victim row one.
p.add_inst(SMC_ACT(BANK_ADDRESS_R, 0, ROW_ADDRESS_R, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); // we activate bank 0 and row 999
p.add_inst(SMC_SLEEP(10)); // nakul
for (int i = 0; i<128; i++) // this writes to the whole dram row that we activated 128 weite commands which takes the bank address and the column address which is a offset in the row since we initialized the data pattern with all 1's its going to write all 1's
{
p.add_inst(SMC_WRITE(BANK_ADDRESS_R, 0, COLUMN_ADDRESS_R, 0, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_ADDI(COLUMN_ADDRESS_R, 8, COLUMN_ADDRESS_R)); //incrementing the column address by 8 by because a single read or write it reaches 8 consecutive columns 512 bits to 8 columns aka 64 bits a column
}
p.add_inst(SMC_SLEEP(10)); //nakul
p.add_inst(SMC_PRE(BANK_ADDRESS_R, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); // sleep just in case and then pre charge as a precaution
p.add_inst(SMC_ADDI(ROW_ADDRESS_R, 1 ,ROW_ADDRESS_R)); // increment the row address register by 1 aka the victim row and i want to initalize the agressor row
p.add_inst(SMC_LI(0, COLUMN_ADDRESS_R)); // reset column address register to 0
// load the aggressor row data pattern // load this with all 0's to initialize the data
for (int i = 0; i < 16; i++)
p.add_inst(SMC_LDWD(DATA_PATTERN_INV_R, i));
// write to the aggressor row
p.add_inst(SMC_ACT(BANK_ADDRESS_R, 0, ROW_ADDRESS_R, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); // same thing as what we did above
p.add_inst(SMC_SLEEP(3));//nakul
for (int i = 0; i < 128; i++)
{
p.add_inst(SMC_WRITE(BANK_ADDRESS_R, 0, COLUMN_ADDRESS_R, 0, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_ADDI(COLUMN_ADDRESS_R, 8, COLUMN_ADDRESS_R));
}
p.add_inst(SMC_SLEEP(10));//nakul
p.add_inst(SMC_PRE(BANK_ADDRESS_R, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
// //write to the second victim row
p.add_inst(SMC_LI(0, COLUMN_ADDRESS_R));
// increment row address register by one
p.add_inst(SMC_ADDI(ROW_ADDRESS_R, 1, ROW_ADDRESS_R));
for (int i = 0; i < 16 ; i++){
p.add_inst(SMC_LDWD(DATA_PATTERN_R, i));}
//from buffer (Row 0):
p.add_inst(SMC_ACT(BANK_ADDRESS_R, 0, ROW_ADDRESS_R, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_SLEEP(10));//nakul
for (int i = 0; i <128 ; i++)
{
p.add_inst(SMC_WRITE(BANK_ADDRESS_R, 0, COLUMN_ADDRESS_R, 0, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_ADDI(COLUMN_ADDRESS_R, 8, COLUMN_ADDRESS_R));
}
p.add_inst(SMC_SLEEP(10));//nakul
p.add_inst(SMC_PRE(BANK_ADDRESS_R, 0 ,0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_LI(0, COLUMN_ADDRESS_R));
p.add_inst(SMC_LI(1000,ROW_ADDRESS_R)); // now we do the attack activate agresser row which is 1000 and we started with 999 initialized 3 rows 999 1000 and 1001 1000 is the agressor
const int HAMMER_COUNTER_R = 10;// counter to perform the attack
const int HAMMER_COUNT_R = 11; // the input from the user
p.add_inst(SMC_LI(hammer_count, HAMMER_COUNT_R));
p.add_inst(SMC_LI(0, HAMMER_COUNTER_R));
p.add_label("HAMMER_BEGIN"); // checks to see if condition is satisfied or not
p.add_inst(SMC_ACT(BANK_ADDRESS_R, 0, ROW_ADDRESS_R, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); // the row hammer attack is only 4 lines
p.add_inst(SMC_SLEEP(24));
p.add_inst(SMC_PRE(BANK_ADDRESS_R, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_ADDI(HAMMER_COUNTER_R, 1, HAMMER_COUNTER_R)); //increase hammer counter by 1
p.add_branch(p.BR_TYPE::BL, HAMMER_COUNTER_R, HAMMER_COUNT_R, "HAMMER_BEGIN"); //branch instrcution this function has 4 arguements aka the type of branchcompares hammer counter to hammer count and if hammer counter is lower than hammer count it will jump back to begin
p.add_inst(SMC_LI(999, ROW_ADDRESS_R)); // read from first victim row
const int READ_COUNTER_R = 10;
const int READ_COUNT_R = 11;
p.add_inst(SMC_LI(3, READ_COUNT_R)); // we want to read thre rows
p.add_inst(SMC_LI(0, READ_COUNTER_R));
p.add_label("READ_BEGIN");
p.add_inst(SMC_ACT(BANK_ADDRESS_R, 0, ROW_ADDRESS_R, 0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_SLEEP(12));
for (int i = 0 ; i < 128 ; i++)
{
p.add_inst(SMC_READ(BANK_ADDRESS_R, 0, COLUMN_ADDRESS_R, 0, 0, 0), SMC_NOP(), SMC_NOP(), SMC_NOP()); //reads the whole row
p.add_inst(SMC_ADDI(COLUMN_ADDRESS_R, 8, COLUMN_ADDRESS_R));
}
p.add_inst(SMC_SLEEP(5));
p.add_inst(SMC_PRE(BANK_ADDRESS_R,0 ,0), SMC_NOP(), SMC_NOP(), SMC_NOP());
p.add_inst(SMC_LI(0, COLUMN_ADDRESS_R));
// increment row address register by one
p.add_inst(SMC_ADDI(ROW_ADDRESS_R, 1, ROW_ADDRESS_R));
p.add_inst(SMC_ADDI(READ_COUNTER_R, 1, READ_COUNTER_R));
p.add_branch(p.BR_TYPE::BL, READ_COUNTER_R, READ_COUNT_R, "READ_BEGIN"); // does it again same as how we did the read
p.add_inst(SMC_END()); // lets dram bender know we finished
platform.execute(p); // executes the program
p.pretty_print();
unsigned char buf1[8192];
int no_bitflips = 0;
// Printing out the data from the buffer
cout << "Data from buffer (Row " << i << "):" << endl;
for (int j = 0; j < 8192; j++) {
cout << setw(2) << setfill('0') << hex << static_cast<int>(buf1[j]) << " ";
if ((j + 1) % 32 == 0) cout << endl; // Change line every 32 bytes for better readability
}
cout << dec << setfill(' ') << endl; // Resetting to default formatting
// Checking for bit flips
for (int j = 0; j < 8192; j++) {
if (expected_bits != buf1[j]) {
no_bitflips += __builtin_popcount(expected_bits ^ buf1[j]);
}
}