From dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f Mon Sep 17 00:00:00 2001 From: Ataberk Date: Sun, 25 Sep 2022 17:22:03 +0200 Subject: Initial commit --- sources/api/prog.cpp | 675 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 675 insertions(+) create mode 100644 sources/api/prog.cpp (limited to 'sources/api/prog.cpp') diff --git a/sources/api/prog.cpp b/sources/api/prog.cpp new file mode 100644 index 0000000..781c079 --- /dev/null +++ b/sources/api/prog.cpp @@ -0,0 +1,675 @@ +#include "instruction.h" +#include "prog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Program::Program() +{ + dumpRegsCalled = false; +} + +Program::Program(std::string fname) +{ + std::cout << "WARNING: make sure that the executable \"smc_parser\" exists in the working directory" << std::endl; + + std::string correctFileName = "./smc_parser " + fname + " < " + fname + " >/dev/null"; + if (system(correctFileName.c_str()) != 0) + { + std::cerr << "Error parsing SMC program, abort." << std::endl; + exit(-1); + } + + // Read instruction binary data from fname.inst + std::ifstream binFile (fname + ".bin", std::ios::in | std::ios::binary); + int no_insts = 0; + // Read no of insts + binFile.read((char*) &no_insts, 4); + Inst insts[no_insts]; + // Read all insts + binFile.read((char*) insts, sizeof(Inst)*no_insts); + for(int i = 0 ; i < no_insts ; i++) + { + program.push_back(insts[i]); + spc++; + } + binFile.close(); + // Read branch label positions from fname.meta + std::ifstream metaFile (fname + ".meta", std::ios::in); + std::string line; + bool parseLabels = true; + while(getline(metaFile,line)) + { + if(parseLabels) + { + if (line == "-") + { + parseLabels = false; + continue; + } + std::string label = line.substr(0,line.find(" ")); + std::string target = line.substr(line.find(" ")+1,line.length()); + (labels)[label] = stoi(target); + } + else + { + std::string target = line.substr(0,line.find(" ")); + std::string label = line.substr(line.find(" ")+1,line.length()); + (branches)[stoi(target)] = label; + } + } + metaFile.close(); +} + + +void Program::add_label(std::string name) +{ + if(labels.count(name)) + std::cerr << "Trying to add label " << name << " multiple times!" << std::endl; + (labels)[name] = spc; +} +void Program::add_wait(int wait_cycles) +{ + for(; wait_cycles > 0 ; wait_cycles--) + { + minprogram.push_back(SMC_NOP()); + } +} + +void Program::add_mininst(Mininst mi, int wait_after) +{ + minprogram.push_back(mi); + for ( ; wait_after>0 ; wait_after--) + minprogram.push_back(SMC_NOP()); + // if (verbose) { + // std::cout << "Added new mininst with wait." << std::endl; + // for(auto& mininst : minprogram){ + // std::cout << std::hex << mininst << " "; + // } + // std::cout << std::endl; + // } +} + +void Program::pack_minprogram() +{ + // if (verbose) std::cout << "Packing minprogram" << std::endl; + while(minprogram.size() >= 4) + { + this->add_inst(__pack_mininsts(minprogram[0], minprogram[1], minprogram[2], minprogram[3])); + minprogram.erase(minprogram.begin(), minprogram.begin()+4); + } + + switch (minprogram.size()) + { + case 0: + return; + case 1: + this->add_inst(__pack_mininsts(minprogram[0], SMC_NOP(), SMC_NOP(), SMC_NOP())); + break; + case 2: + this->add_inst(__pack_mininsts(minprogram[0], minprogram[1], SMC_NOP(), SMC_NOP())); + break; + case 3: + this->add_inst(__pack_mininsts(minprogram[0], minprogram[1], minprogram[2], SMC_NOP())); + break; + } + // std::cerr << "WARNING: Number of mininsts is not multiple of four. " + // << "Appending "<< 4-minprogram.size() << " extra NOPs for alignment." + // << std::endl; + minprogram.erase(minprogram.begin(), minprogram.end()); +} + +void Program::add_inst(Inst i) +{ + program.push_back(i); + if (is_load(i)) + this->add_inst(SMC_NOP(), SMC_NOP(), SMC_NOP(), SMC_NOP()); + spc += 1; +} + +void Program::add_inst(Mininst m1, Mininst m2, Mininst m3, Mininst m4) +{ + Inst i = (uint64_t) m4 << 48 | + (uint64_t) m3 << 32 | + (uint64_t) m2 << 16 | + m1; + program.push_back(i); + spc += 1; +} + +void Program::add_branch(BR_TYPE bt, int rs1, int rs2, std::string tgt) +{ + Inst place_holder = 2; + switch(bt) + { + case BR_TYPE::BL: + place_holder = SMC_BL(rs1, rs2, 0); + break; + case BR_TYPE::BEQ: + place_holder = SMC_BEQ(rs1, rs2, 0); + break; + case BR_TYPE::JUMP: + place_holder = SMC_JUMP(0); + break; + } + (branches)[spc] = tgt; + add_inst(place_holder); +} + +void Program::add_below(const Program &p) +{ + // move instructions from p to the end of + // this program + program.insert(program.end(), p.program.begin(), p.program.end()); + + // update branch targets and branch instruction pcs + for ( const auto &branch : (p.branches) ) + ((this->branches))[branch.first + this -> spc] = branch.second; + + for ( const auto &label : (p.labels) ) + ((this->labels))[label.first] = label.second + this -> spc; + + // update pc + this -> spc += p.spc; +} + +Inst* Program::get_inst_array() +{ + linear_analysis(); + insert_generated(); +// printf("Inserted auto-generated info instructions\n"); + preprocess_branches(); +// printf("Assigned branch targets to labels\n"); + //pretty_print(); + int bytes = size(); + Inst* arr = (Inst*) malloc(bytes); + int ind = 0; + for (auto & element : (program)) + arr[ind++] = element; + return arr; +} + +Inst* Program::get_insts() +{ + int bytes = size(); + Inst* arr = (Inst*) malloc(bytes); + int ind = 0; + for (auto & element : (program)) + arr[ind++] = element; + return arr; +} + +int Program::size() +{ + return program.size() * 8; +} + +void Program::preprocess_branches() +{ + for ( const auto &branch : (branches) ) { + Inst br = (program)[branch.first]; + int lbl = (labels)[branch.second]; +// printf("branch addr: %d branch label: %s lbl_adr: %d is_cond: %d\n", branch.first, branch.second.c_str(), +// lbl,is_conditional(br)); + assert(is_branch(br) && + "preprocess_branches(): expected a branch but got something else"); + uint64_t target_b = ((uint64_t)lbl) << 8; + uint64_t target_j = (uint64_t) lbl; + br |= is_conditional(br) ? target_b : target_j; + (program)[branch.first] = br; + } +} + +/** + * Currently only goes through the whole program + * to see if any constraint is violated + */ +void Program::linear_analysis() +{ + bool inSequence = false; + uint seqPc = 0; + int readCtr = 0; + for (uint pc = 0 ; pc < program.size() ; pc++) + { + Inst cur_inst = (program)[pc]; + if(!inSequence) + { + if(is_ddr(cur_inst)) + { + //printf("Program::linear_analysis(): enter segment at pc: %d\n", pc); + inSequence = true; + seqPc = pc; + readCtr = is_ddr_read(cur_inst); + } + }else + { + // we see a non-ddr inst, + // can commit whatever info we want + // related to the previous segment + if(!is_ddr(cur_inst) && !is_sleep(cur_inst)) + { + //printf("Program::linear_analysis(): exit segment at pc: %d with %d reads \n", pc, readCtr); + inSequence = false; + // TODO either directly insert into the vector + // or keep these records elsewhere + if(readCtr > 1024) + { + // TODO Add code that will warn user violently here. + // maybe even an assertion? + std::cerr << "WARNING: SoftMC won't be able to run your program timing-critically!" << std::endl; + }else if(readCtr > 0) + { + // Insert info-encapsulating packet into program + Inst warn_pipeline = SMC_INFO(readCtr); + (warnings)[seqPc] = warn_pipeline; + } + }else + { + readCtr += is_ddr_read(cur_inst); + } + } + } +} + + +void Program::insert_generated() +{ + // WARNING this assumes that map keys are iterated + // in ascending order + + std::vector warn_keys; + std::vector warn_values; + + for ( const auto &warn : (this->warnings)) + { + warn_keys.push_back(warn.first); + warn_values.push_back(warn.second); + } + + while (warn_keys.size()>0) + { + // new branch and label mappings + uint warn_key = warn_keys.front(); + Inst warn_value = warn_values.front(); + warn_keys.erase(warn_keys.begin()); + warn_values.erase(warn_values.begin()); + + std::map n_labels; + std::map n_branches; + program.insert(program.begin() + warn_key, warn_value); + for ( const auto &branch : (this->branches) ) + { + // branch target > inserted instruction pc + if((labels)[branch.second] > warn_key) + { + (n_labels)[branch.second] = (labels)[branch.second] + 1; + }else + { + (n_labels)[branch.second] = (labels)[branch.second]; + } + // branching instruction pc > inserted instruction pc + if(branch.first >= warn_key) + { + (n_branches)[branch.first + 1] = branch.second; + }else + { + (n_branches)[branch.first] = branch.second; + } + } + for (uint i = 0 ; i < warn_keys.size() ; i++) + warn_keys[i] += 1; + + labels = n_labels; + branches = n_branches; + } +} + +void Program::pretty_print() +{ + for (uint pc = 0 ; pc < program.size() ; pc++) + { + for ( const auto &label : (labels) ) + { + if(label.second == pc) + std::cout << label.first << std::endl; + } + printf("%04d: ", pc); + decode_inst((program)[pc]); + for ( const auto &branch : (branches) ) + { + if(branch.first == pc) + std::cout << " (TARGET LABEL: " << branch.second << ")"; + } + printf("\n"); + } + +} + +void Program::bin_dump() +{ + for (uint pc = 0 ; pc < program.size() ; pc++) + { + for ( const auto &label : (labels) ) + { + if(label.second == pc) + std::cout << label.first << std::endl; + } + std::cout << "PC: " << pc << " Inst: " << std::hex << (program)[pc] << std::dec << std::endl; + + for ( const auto &branch : (branches) ) + { + if(branch.first == pc) + std::cout << branch.second; + } + printf("\n"); + } +} + +void Program::save_bin(const std::string &fname) +{ + // Write instruction binary data to fname.inst + std::ofstream binFile (fname + ".bin", std::ios::out | std::ios::binary); + Inst* insts = this -> get_insts(); + int no_insts = spc; + binFile.write ((char*)&no_insts, sizeof(no_insts)); + binFile.write ((char*) insts, sizeof(Inst)*no_insts); + binFile.close(); + // Write branch label positions to fname.meta + std::ofstream metaFile (fname + ".meta", std::ios::out); + for ( const auto &label : (labels) ) + metaFile << label.first << " " << label.second << "\n"; + metaFile << "-" << "\n"; + for ( const auto &branch : (branches) ) + metaFile << branch.first << " " << branch.second << "\n"; + metaFile.close(); +} + +void Program::save_coe_here(const std::string &prj_dir) +{ + std::ofstream coeFile ("program.coe", std::ios::out | std::ios::binary); + uint64_t* insts = (uint64_t*) this -> get_inst_array(); + coeFile << "memory_initialization_radix=2;\n"; + coeFile << "memory_initialization_vector=\n"; + for(uint i = 0 ; i < program.size() ; i++){ + coeFile << std::bitset<64>(insts[i]); + if( i == (program.size()) -1){ + coeFile << ";"; + }else{ + coeFile << ",\n"; + } + } + coeFile.close(); +} + + +void Program::save_coe(const std::string &prj_dir) +{ + std::ofstream coeFile (prj_dir + "/VU095.sim/sim_1/behav/xsim/simmem.coe", std::ios::out | std::ios::binary); + std::ofstream coeFile2 (prj_dir + "/coe/simmem.coe", std::ios::out | std::ios::binary); + std::ofstream mifFile (prj_dir + "/VU095.sim/sim_1/behav/xsim/instr_blk_mem_sim.mif", std::ios::out | std::ios::binary); + uint64_t* insts = (uint64_t*) this -> get_inst_array(); + coeFile << "memory_initialization_radix=2;\n"; + coeFile2 << "memory_initialization_radix=2;\n"; + coeFile << "memory_initialization_vector=\n"; + coeFile2 << "memory_initialization_vector=\n"; + for(uint i = 0 ; i < program.size() ; i++){ + coeFile << std::bitset<64>(insts[i]); + coeFile2 << std::bitset<64>(insts[i]); + mifFile << std::bitset<64>(insts[i])<<"\n"; + if( i == (program.size()) -1){ + coeFile << ";"; + coeFile2 << ";"; + }else{ + coeFile << ",\n"; + coeFile2 << ",\n"; + } + } + coeFile.close(); + coeFile2.close(); + mifFile.close(); +} + + +void Program::dump_registers() +{ + if(dumpRegsCalled) + { + std::cerr << "You can use your trump card (dump_register) only once per program!" << std::endl; + exit(1); + } + dumpRegsCalled = true; + + this -> add_inst(SMC_LI(15,13)); // BAR + this -> add_inst(SMC_LI(0,14)); // RAR + this -> add_inst(SMC_LI(0,15)); // CAR + + this -> add_inst(__pack_mininsts(SMC_PRE(13,0,1), // PRECHARGE ALL + SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_ACT(13,0,14,0), // ACT B15 R0 + SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_WRITE(13,0,15,0,0,0), // WRITE WDATA CONTENT + SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_READ(13,0,15,0,0,0), // READ WDATA CONTENT + SMC_NOP(),SMC_NOP(),SMC_NOP())); + + for (int i = 0 ; i < 16 ; i++) // SWAP WDATA WITH REG VALUES + this -> add_inst(SMC_LDWD(i,i)); + + this -> add_inst(__pack_mininsts(SMC_WRITE(13,0,15,0,0,0), // WRITE WDATA CONTENT + SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_READ(13,0,15,0,0,0), // READ WDATA CONTENT + SMC_NOP(),SMC_NOP(),SMC_NOP())); + + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_NOP(),SMC_NOP(),SMC_NOP(),SMC_NOP())); + this -> add_inst(__pack_mininsts(SMC_PRE(13,0,1), // PRECHARGE ALL + SMC_NOP(),SMC_NOP(),SMC_NOP())); +} + +bool Program::isDumpRegsCalled() +{ + return dumpRegsCalled; +} + +void Program::debug(const std::string &prj_dir, bool first) +{ + int pid = fork(); + if(pid == 0){ + + std::string source = prj_dir + "/source.tcl"; + std::string project = prj_dir + "/VU095.xpr"; + std::string arg; + int fd = open("/dev/null", O_WRONLY); + dup2(fd, 1); + if(first) + arg = "first"; + else + arg = "debug"; + + execl("/opt/Xilinx/Vivado/2018.2/bin/vivado", + "vivado","-mode","tcl","-nojournal","-applog","-log","/tmp/asmc.log", + "-source", source.c_str(), project.c_str(),"-tclargs", arg.c_str(), NULL); + + }else if(pid > 0){ + std::cout << "Debugger starting...\n"; + + mkfifo("/tmp/fifo_1", 0666); + int f1 = open("/tmp/fifo_1", O_WRONLY); + mkfifo("/tmp/fifo_2", 0666); + int f2 = open("/tmp/fifo_2", O_RDONLY); + + char buf[100]; + [[maybe_unused]] int rv; + + std::vector vios; + std::string line, start, end, vio; + + start = "sim_tb_top.mem_model_x8.memModels_Ri1[0].memModel1[0].ddr4_model.always_diff_ck.if_diff_ck:VIOLATION:"; + end = "sim_tb_top.mem_model_x8.memModels_Ri1[0].memModel1[1].ddr4_model.always_diff_ck.if_diff_ck:VIOLATION:"; + + std::string msg, com, param,param2; + std::vector commands {"reg", "mem", "time", "step", "run", + "until", "exit", "btwn","stat"}; + + int state = 0; + + while(state != 5){ + switch (state){ + case 0: + std::cout << "Enter command: "; + std::cin >> com; + if(std::find(commands.begin(), commands.end(), com) != commands.end()){ + if(com == "step" || com == "exit" || com == "time" || com == "stat"){ + msg = com + "_\n"; + }else if(com == "btwn"){ + std::cin >> param; + std::cin >> param2; + msg = com + "_" + param + "_" + param2 + "\n"; + }else{ + std::cin >> param; + msg = com + "_" + param + "\n"; + } + state = 1; + }else{ + std::cout << "Please enter a valid command...\n"; + } + break; + + case 1: + rv = write( f1, (char*)msg.c_str(), msg.size()); + memset(buf, 0, sizeof(buf)); + while(read(f2, buf, sizeof(buf)) == 0); + state = 2; + break; + + case 2: + if(com == "reg" || com == "mem") + std::cout << com << " " << param << ": " << buf; + else if(com == "btwn") + std::cout << "Time between "<< param << "-" << param2 << ": " << buf; + else if(com == "time") + std::cout << "Current time: " << buf; + else if(com == "stat") + std::cout << "Stats:\n" << buf; + else if(com == "exit"){ + state = 5; + break; + } + state = 3; + break; + + case 3: + std::ifstream logfile ("/tmp/asmc.log"); + while (std::getline(logfile, line)) + { + if(line.find(start) != std::string::npos) + { + vio = line; + if(std::find(vios.begin(), vios.end(), vio) != vios.end()) + continue; + std::cout << line.substr(91) << "\n"; + while (std::getline(logfile, line)) + { + if (line.find(end) != std::string::npos) + break; + std::cout << line << "\n"; + } + vios.insert(vios.begin(), vio); + } + } + logfile.close(); + state = 0; + break; + + } + } + close(f1); + close(f2); + wait(NULL); + remove("/tmp/fifo_1"); + remove("/tmp/fifo_2"); + remove("/tmp/asmc.log"); + std::cout << "Exiting debugger.\n"; + } +} + +void Program::debug(const std::string &prj_dir, const std::string &filename) +{ + int pid = fork(); + if(pid == 0){ + + std::string source = prj_dir + "/source.tcl"; + std::string project = prj_dir + "/VU095.xpr"; + int fd = open("/dev/null", O_WRONLY); + dup2(fd, 1); + execl("/opt/Xilinx/Vivado/2018.2/bin/vivado", + "vivado","-mode","tcl","-nojournal","-applog","-log","/tmp/asmc.log", + "-source", source.c_str(), project.c_str(),"-tclargs", "update", NULL); + + }else if(pid > 0){ + + std::string path, line, param, value, time_path, temp_path; + + path = prj_dir.substr(0, prj_dir.find("VU095")) + "phy_ddr4_ex/imports/"; + time_path = path + "timing_tasks.sv"; + temp_path = path + "temp.sv"; + + std::ifstream timing_tasks (time_path); + std::ifstream param_file (filename); + std::ofstream temp_file (temp_path); + + std::map params; + + while (std::getline(param_file, line)){ + param = line.substr(0, line.find("=")); + param = param.substr(param.find_first_not_of(" \n\r\t\f\v"),param.find_last_not_of(" \n\r\t\f\v") + 1); + param = " SetTSArray (i" + param; + value = line.substr(line.find("=") + 1); + value = value.substr(value.find_first_not_of(" \n\r\t\f\v"),value.find_last_not_of(" \n\r\t\f\v") + 1); + value = std::string((7- value.size()), ' ') + value; + params[param] = value; + } + param_file.close(); + + while (std::getline(timing_tasks, line)){ + if(line.find(" SetTSArray (i") == std::string::npos){ + temp_file << line << "\n"; + continue; + } + for(const auto & param : params){ + if(line.find(param.first) != std::string::npos){ + line = line.replace(35, 7, param.second); + break; + } + } + temp_file << line << "\n"; + } + + timing_tasks.close(); + temp_file.close(); + remove(time_path.c_str()); + rename(temp_path.c_str(), time_path.c_str()); + wait(NULL); + std::cout << "Timing parameters are updated...\n"; + } +} -- cgit v1.2.3