#ifdef SYSTEMC /* * $Id: Load_store_unit_function_speculative_load_access_transition.cpp 138 2010-05-12 17:34:01Z rosiere $ * * [ Description ] * */ #include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Multi_Execute_unit/Execute_unit/Load_store_unit/include/Load_store_unit.h" #include "Behavioural/include/Identification.h" namespace morpheo { namespace behavioural { namespace core { namespace multi_execute_loop { namespace execute_loop { namespace multi_execute_unit { namespace execute_unit { namespace load_store_unit { template T swapBytes (T data, uint32_t size_data, uint32_t size_access) { uint64_t x = static_cast(data); // switch (size_data) // { // case 2 : // 16 bits // { // switch (size_access) // { // case 2 : // { // x = ((((x>> 8)&0xff) << 0) | // (((x>> 0)&0xff) << 8) ); // break; // } // default : // { // break; // } // } // break; // } // case 4 : // 32 bits // { // switch (size_access) // { // case 2 : // { // x = ((((x>> 8)&0xff) << 0) | // (((x>> 0)&0xff) << 8) | // (((x>>24)&0xff) << 16) | // (((x>>16)&0xff) << 24) ); // break; // } // case 4 : // { // x = ((((x>>24)&0xff) << 0) | // (((x>>16)&0xff) << 8) | // (((x>> 8)&0xff) << 16) | // (((x>> 0)&0xff) << 24) ); // break; // } // default : // { // break; // } // } // break; // } // case 8 : // 64 bits // { // switch (size_access) // { // case 2 : // { // x = ((((x>> 8)&0xff) << 0) | // (((x>> 0)&0xff) << 8) | // (((x>>24)&0xff) << 16) | // (((x>>16)&0xff) << 24) | // (((x>>40)&0xff) << 32) | // (((x>>32)&0xff) << 40) | // (((x>>56)&0xff) << 48) | // (((x>>48)&0xff) << 56) ); // break; // } // case 4 : // { // x = ((((x>>24)&0xff) << 0) | // (((x>>16)&0xff) << 8) | // (((x>> 8)&0xff) << 16) | // (((x>> 0)&0xff) << 24) | // (((x>>56)&0xff) << 32) | // (((x>>48)&0xff) << 40) | // (((x>>40)&0xff) << 48) | // (((x>>32)&0xff) << 56) ); // break; // } // case 8 : // { // x = ((((x>>56)&0xff) << 0) | // (((x>>48)&0xff) << 8) | // (((x>>40)&0xff) << 16) | // (((x>>32)&0xff) << 24) | // (((x>>24)&0xff) << 32) | // (((x>>16)&0xff) << 40) | // (((x>> 8)&0xff) << 48) | // (((x>> 0)&0xff) << 56) ); // break; // } // default : // { // break; // } // } // break; // } // default : // { // break; // } // } uint64_t y=0; for (uint32_t i=0; i>( 8+offset))&0xff) << ( 0+offset)) | (((x>>( 0+offset))&0xff) << ( 8+offset)) ); break; } case 4 : { y |= ((((x>>(24+offset))&0xff) << ( 0+offset)) | (((x>>(16+offset))&0xff) << ( 8+offset)) | (((x>>( 8+offset))&0xff) << (16+offset)) | (((x>>( 0+offset))&0xff) << (24+offset)) ); break; } case 8 : { y |= ((((x>>(56+offset))&0xff) << ( 0+offset)) | (((x>>(48+offset))&0xff) << ( 8+offset)) | (((x>>(40+offset))&0xff) << (16+offset)) | (((x>>(32+offset))&0xff) << (24+offset)) | (((x>>(24+offset))&0xff) << (32+offset)) | (((x>>(16+offset))&0xff) << (40+offset)) | (((x>>( 8+offset))&0xff) << (48+offset)) | (((x>>( 0+offset))&0xff) << (56+offset)) ); break; } default : { break; } } } return static_cast(y); } template T swapBits (T data, uint32_t size_data, uint32_t size_access) { uint8_t x = static_cast(data); uint8_t y=0; for (uint32_t i=0; i>( 1+offset))&0x1) << ( 0+offset)) | (((x>>( 0+offset))&0x1) << ( 1+offset)) ); break; } case 4 : { y |= ((((x>>( 3+offset))&0x1) << ( 0+offset)) | (((x>>( 2+offset))&0x1) << ( 1+offset)) | (((x>>( 1+offset))&0x1) << ( 2+offset)) | (((x>>( 0+offset))&0x1) << ( 3+offset)) ); break; } case 8 : { y |= ((((x>>( 7+offset))&0x1) << ( 0+offset)) | (((x>>( 6+offset))&0x1) << ( 1+offset)) | (((x>>( 5+offset))&0x1) << ( 2+offset)) | (((x>>( 4+offset))&0x1) << ( 3+offset)) | (((x>>( 3+offset))&0x1) << ( 4+offset)) | (((x>>( 2+offset))&0x1) << ( 5+offset)) | (((x>>( 1+offset))&0x1) << ( 6+offset)) | (((x>>( 0+offset))&0x1) << ( 7+offset)) ); break; } default : { break; } } } return static_cast(y); } #undef FUNCTION #define FUNCTION "Load_store_unit::function_speculative_load_access_transition" void Load_store_unit::function_speculative_load_access_transition (void) { log_begin(Load_store_unit,FUNCTION); log_function(Load_store_unit,FUNCTION,_name.c_str()); if (PORT_READ(in_NRESET) == 0) { // Reset : clear all queue _speculative_access_queue_control->clear(); reg_STORE_QUEUE_PTR_READ = 0; reg_LOAD_QUEUE_CHECK_PRIORITY = 0; for (uint32_t i=0; i< _param->_size_store_queue ; i++) { reg_STORE_QUEUE_NB_CHECK [i] = 0; // reg_STORE_QUEUE_INVALID [i] = 0; _store_queue [i]._state = STORE_QUEUE_EMPTY; _store_queue [i]._context_id = 0; // not necessary _store_queue [i]._front_end_id = 0; // not necessary _store_queue [i]._ooo_engine_id = 0; // not necessary _store_queue [i]._packet_id = 0; // not necessary _store_queue [i]._operation = 0; // not necessary _store_queue [i]._cancel = 0; // not necessary _store_queue [i]._load_queue_ptr_write = 0; // not necessary _store_queue [i]._address = 0; // not necessary _store_queue [i]._wdata = 0; // not necessary // _store_queue [i]._write_rd = 0; // not necessary // _store_queue [i]._num_reg_rd = 0; // not necessary _store_queue [i]._exception = 0; // not necessary _store_queue [i]._send_commit = 0; // not necessary } for (uint32_t i=0; i< _param->_size_load_queue ; i++) { _load_queue [i]._state = LOAD_QUEUE_EMPTY; _load_queue [i]._context_id = 0; // not necessary _load_queue [i]._front_end_id = 0; // not necessary _load_queue [i]._ooo_engine_id = 0; // not necessary _load_queue [i]._packet_id = 0; // not necessary _load_queue [i]._operation = 0; // not necessary _load_queue [i]._cancel = 0; // not necessary _load_queue [i]._store_queue_ptr_write = 0; // not necessary _load_queue [i]._store_queue_ptr_read = 0; // not necessary _load_queue [i]._store_queue_empty = 0; // not necessary _load_queue [i]._address = 0; // not necessary _load_queue [i]._check_hit_byte = 0; // not necessary _load_queue [i]._check_hit = 0; // not necessary _load_queue [i]._shift = 0; // not necessary _load_queue [i]._is_load_signed = 0; // not necessary _load_queue [i]._access_size = 0; // not necessary _load_queue [i]._rdata = 0; // not necessary _load_queue [i]._write_rd = 0; // not necessary _load_queue [i]._num_reg_rd = 0; // not necessary _load_queue [i]._exception = 0; // not necessary _load_queue [i]._can_speculative_commit= 0; // not necessary } for (uint32_t i=0; i< _param->_size_speculative_access_queue; i++) { _speculative_access_queue [i]._state = SPECULATIVE_ACCESS_QUEUE_EMPTY; _speculative_access_queue [i]._context_id = 0; // not necessary _speculative_access_queue [i]._front_end_id = 0; // not necessary _speculative_access_queue [i]._ooo_engine_id = 0; // not necessary _speculative_access_queue [i]._packet_id = 0; // not necessary _speculative_access_queue [i]._operation = 0; // not necessary _speculative_access_queue [i]._cancel = 0; // not necessary _speculative_access_queue [i]._load_queue_ptr_write = 0; // not necessary _speculative_access_queue [i]._store_queue_ptr_write = 0; // not necessary _speculative_access_queue [i]._store_queue_ptr_read = 0; // not necessary _speculative_access_queue [i]._store_queue_empty = 0; // not necessary _speculative_access_queue [i]._address = 0; // not necessary _speculative_access_queue [i]._write_rd = 0; // not necessary _speculative_access_queue [i]._num_reg_rd = 0; // not necessary _speculative_access_queue [i]._exception = 0; // not necessary } } else { // load_queue_push if speculative_access_queue have access at the dcache, or they have an event bool load_queue_push = (_speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._state == SPECULATIVE_ACCESS_QUEUE_WAIT_LOAD_QUEUE); //================================================================ // Interface "MEMORY_OUT" //================================================================ if (( internal_MEMORY_OUT_VAL == 1) and (PORT_READ(in_MEMORY_OUT_ACK[0]) == 1)) { log_printf(TRACE,Load_store_unit,FUNCTION," * MEMORY_OUT[0] transaction"); switch (internal_MEMORY_OUT_SELECT_QUEUE) { case SELECT_STORE_QUEUE : { // ======================= // ===== STORE_QUEUE ===== // ======================= log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue [%d]",internal_MEMORY_OUT_PTR); // Entry flush and increase the read pointer if (_store_queue [internal_MEMORY_OUT_PTR]._send_commit) { _store_queue [internal_MEMORY_OUT_PTR]._state = STORE_QUEUE_EMPTY; reg_STORE_QUEUE_PTR_READ = (reg_STORE_QUEUE_PTR_READ+1)%_param->_size_store_queue; } else _store_queue [internal_MEMORY_OUT_PTR]._send_commit = true; break; } case SELECT_LOAD_QUEUE : { // ====================== // ===== LOAD_QUEUE ===== // ====================== log_printf(TRACE,Load_store_unit,FUNCTION," * load_queue [%d]",internal_MEMORY_OUT_PTR); // Entry flush and increase the read pointer _load_queue [internal_MEMORY_OUT_PTR]._state = LOAD_QUEUE_EMPTY; // reg_LOAD_QUEUE_PTR_READ = (reg_LOAD_QUEUE_PTR_READ+1)%_param->_size_load_queue; break; } case SELECT_LOAD_QUEUE_SPECULATIVE : { log_printf(TRACE,Load_store_unit,FUNCTION," * load_queue [%d] (speculative)",internal_MEMORY_OUT_PTR); // !!! WARNING !!! // !!! Test special case : // !!! in a cycle an instruction can check the last store AND commit instruction // !!! also the memory_out is before the port_check _load_queue [internal_MEMORY_OUT_PTR]._state = LOAD_QUEUE_CHECK; // NOTE : a speculative load write in the register file. // if the speculation is a miss, write_rd is re set at 1. _load_queue [internal_MEMORY_OUT_PTR]._write_rd = 0; #ifdef STATISTICS if (usage_is_set(_usage,USE_STATISTICS)) (*_stat_nb_inst_load_commit_speculative) ++; #endif break; } break; } } //================================================================ // Interface "PORT_CHECK" //================================================================ // Plusieurs moyens de faire la verification de dépendance entre les loads et les stores. // 1) un load ne peut vérifier qu'un store par cycle. Dans ce cas port_check <= size_load_queue // 2) un load tente de vérifier le maximum de store par cycle. Dans ce cas ce n'est pas du pointeur d'écriture qu'il lui faut mais un vecteur de bit indiquant quel store à déjà été testé. De plus il faut un bit indiquant qu'il y a un match mais que ce n'est pas forcément le premier. // solution 1) log_printf(TRACE,Load_store_unit,FUNCTION," * CHECK"); for (uint32_t i=0, nb_check=0; (nb_check<_param->_nb_port_check) and (i<_param->_size_load_queue); i++) { // Get an index from load queue uint32_t index_load_queue = (i + reg_LOAD_QUEUE_CHECK_PRIORITY)%_param->_size_load_queue; // Test if this load must ckecked store queue if (((_load_queue[index_load_queue]._state == LOAD_QUEUE_WAIT_CHECK) or (_load_queue[index_load_queue]._state == LOAD_QUEUE_COMMIT_CHECK) or (_load_queue[index_load_queue]._state == LOAD_QUEUE_CHECK)) and is_operation_memory_load(_load_queue[index_load_queue]._operation)) { log_printf(TRACE,Load_store_unit,FUNCTION," * Find a load : %d",index_load_queue); nb_check++; // use one port // find a entry that it need a check Tlsq_ptr_t store_queue_ptr_write = _load_queue[index_load_queue]._store_queue_ptr_write; Tlsq_ptr_t store_queue_ptr_read = _load_queue[index_load_queue]._store_queue_ptr_read ; Tlsq_ptr_t store_queue_empty = _load_queue[index_load_queue]._store_queue_empty ; // Tlsq_ptr_t store_queue_ptr_write_old = store_queue_ptr_write; // Init variable bool end_check = false; bool change_state = false; bool next = false; // At the first store queue empty, stop check. // Explication : // * rename logic keep a empty case in the store queue (also size_store_queue > 1) // * when a store is out of store queue, also it was in head of re order buffer. Also, they are none previous load. log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_write : %d",store_queue_ptr_write); log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_read : %d",store_queue_ptr_read ); // log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_empty : %d",store_queue_empty ); log_printf(TRACE,Load_store_unit,FUNCTION," * reg_STORE_QUEUE_PTR_READ : %d",reg_STORE_QUEUE_PTR_READ); if ((store_queue_ptr_write == store_queue_ptr_read) or (store_queue_ptr_write == reg_STORE_QUEUE_PTR_READ)) // if (store_queue_empty) { log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_write == store_queue_ptr_read"); end_check = true; change_state = true; } else { log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_write != store_queue_ptr_read"); store_queue_ptr_write = (store_queue_ptr_write-1)%(_param->_size_store_queue); // store_queue_ptr_write target the next slot to write, also the slot is not significatif when the load is renaming log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_write : %d",store_queue_ptr_write); bool test_thread_id = true; // Test thread id if (_param->_have_port_context_id) test_thread_id &= (_load_queue[index_load_queue]._context_id == _store_queue[store_queue_ptr_write]._context_id); if (_param->_have_port_front_end_id) test_thread_id &= (_load_queue[index_load_queue]._front_end_id == _store_queue[store_queue_ptr_write]._front_end_id); if (_param->_have_port_ooo_engine_id) test_thread_id &= (_load_queue[index_load_queue]._ooo_engine_id == _store_queue[store_queue_ptr_write]._ooo_engine_id); // switch on store_queue state switch (_store_queue[store_queue_ptr_write]._state) { case STORE_QUEUE_VALID_NO_SPECULATIVE : case STORE_QUEUE_COMMIT : case STORE_QUEUE_VALID_SPECULATIVE : { log_printf(TRACE,Load_store_unit,FUNCTION," * store have a valid entry"); // TODO : MMU - nous considérons que les adresses sont physique if (test_thread_id) { // the load and store are in the same thread. Now, we must test address. log_printf(TRACE,Load_store_unit,FUNCTION," * load and store is the same thread."); Tdcache_address_t load_addr = _load_queue [index_load_queue ]._address; Tdcache_address_t store_addr = _store_queue[store_queue_ptr_write]._address; log_printf(TRACE,Load_store_unit,FUNCTION," * load_addr : %.8x.",load_addr ); log_printf(TRACE,Load_store_unit,FUNCTION," * store_addr : %.8x.",store_addr); log_printf(TRACE,Load_store_unit,FUNCTION," * load_addr & mask_address_msb : %.8x.",load_addr & _param->_mask_address_msb); log_printf(TRACE,Load_store_unit,FUNCTION," * store_addr & mask_address_msb : %.8x.",store_addr & _param->_mask_address_msb); // Test if the both address target the same "word" if ((load_addr & _param->_mask_address_msb) == (store_addr & _param->_mask_address_msb)) { log_printf(TRACE,Load_store_unit,FUNCTION," * address_msb is the same."); // all case - [] : store, () : load // (1) store_max >= load_max and store_min <= load_min ...[...(...)...]... Ok - inclusion in store // (2) store_min > load_max ...[...]...(...)... Ok - no conflit // (3) store_max < load_min ...(...)...[...]... Ok - no conflit // (4) store_max < load_max and store_min > load_min ...(...[...]...)... Ko - inclusion in load // (5) store_max >= load_max and store_min > load_min ...[...(...]...)... Ko - conflit // (6) store_max < load_max and store_min <= load_min ...(...[...)...]... Ko - conflit // but : // load in the cache is a word ! // the mask can be make when the load is commited. Also, the rdata content a full word. // the only case is (4) // Read data bool is_big_endian = true; Tgeneral_data_t load_data = _load_queue [index_load_queue ]._rdata ; Tgeneral_data_t store_data = _store_queue[store_queue_ptr_write]._wdata ; Tdcache_address_t check_hit_byte = _load_queue [index_load_queue ]._check_hit_byte; Tcontrol_t check_hit = _load_queue [index_load_queue ]._check_hit; uint32_t load_size_access = memory_size(_load_queue [index_load_queue ]._operation)>>3; uint32_t store_size_access = memory_size(_store_queue[store_queue_ptr_write]._operation)>>3; log_printf(TRACE,Load_store_unit,FUNCTION," * is_big_endian : %d",is_big_endian); log_printf(TRACE,Load_store_unit,FUNCTION," * load_data : 0x%.8x",load_data); log_printf(TRACE,Load_store_unit,FUNCTION," * store_data : 0x%.8x",store_data); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit_byte : %x",check_hit_byte); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit : %d",check_hit); log_printf(TRACE,Load_store_unit,FUNCTION," * load_size_access : %d",load_size_access ); log_printf(TRACE,Load_store_unit,FUNCTION," * store_size_access : %d",store_size_access); if (is_big_endian) { // swap in little endian load_data = swapBytes(load_data , _param->_size_general_data>>3,load_size_access); store_data = swapBytes(store_data , _param->_size_general_data>>3,store_size_access); check_hit_byte = swapBits (check_hit_byte, _param->_size_general_data>>3,load_size_access); log_printf(TRACE,Load_store_unit,FUNCTION," * load_data (swap 1) : 0x%.8x",load_data); log_printf(TRACE,Load_store_unit,FUNCTION," * store_data (swap 1) : 0x%.8x",store_data); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit_byte (swap 1) : %x",check_hit_byte); } uint32_t store_nb_byte = (1<_mask_address_lsb); uint32_t store_num_byte_max = store_num_byte_min+store_nb_byte; log_printf(TRACE,Load_store_unit,FUNCTION," * store_num_byte_min : %d",store_num_byte_min); log_printf(TRACE,Load_store_unit,FUNCTION," * store_num_byte_max : %d",store_num_byte_max); // The bypass is checked byte per byte // Is same endianness : because to change endianness, we must write in special register. Also the pipeline is flushed. for (uint32_t num_store_byte=store_num_byte_min; num_store_byte> 0 // // lw 0 : 0 1 2 3 >> 0 -4 // // lw 4 : 4 5 6 7 >> 32 +4 // // lh 0 : 0 1 >> 0 -6 // // lh 2 : 2 3 >> 16 -2 // // lh 4 : 4 5 >> 32 +2 // // lh 6 : 6 7 >> 48 +6 // // lb 0 : 0 >> 0 -7 // // lb 1 : 1 >> 8 -5 // // lb 2 : 2 >> 16 -3 // // lb 3 : 3 >> 24 -1 // // lb 4 : 4 >> 32 +1 // // lb 5 : 5 >> 40 +3 // // lb 6 : 6 >> 48 +5 // // lb 7 : 7 >> 56 +7 // // diff : (store_nb_byte + load_nb_byte) - 2*nb_load_byte*((num_store_byte+1) // // store duplicate = all store access can be see as full size_data store // // uint32_t load_nb_byte = (1<_size_general_data>>3)+load_nb_byte-2*load_nb_byte*((num_store_byte/load_nb_byte)+1)); // // num_load_byte =num_store_byte+diff; // // log_printf(TRACE,Load_store_unit,FUNCTION," * load_nb_byte : %d",load_nb_byte); // // log_printf(TRACE,Load_store_unit,FUNCTION," * diff : %d",diff); // num_load_byte = num_store_byte; // } // else // { // // sd 0 : 0 1 2 3 4 5 6 7 // // ld 0 : 0 1 2 3 4 5 6 7 >> 0 // // lw 0 : 4 5 6 7 >> 0 // // lw 4 : 0 1 2 3 >> 32 // // lh 0 : 6 7 >> 0 // // lh 2 : 4 5 >> 16 // // lh 4 : 2 3 >> 32 // // lh 6 : 0 1 >> 48 // // lb 0 : 7 >> 0 // // lb 1 : 6 >> 8 // // lb 2 : 5 >> 16 // // lb 3 : 4 >> 24 // // lb 4 : 3 >> 32 // // lb 5 : 2 >> 40 // // lb 6 : 1 >> 48 // // lb 7 : 0 >> 56 // num_load_byte = num_store_byte; // } uint32_t mask = 1<>num_store_bit_min) & 0xff) << num_load_bit_min) | mask_not(load_data,num_load_bit_max,num_load_bit_min)); check_hit_byte |= mask; check_hit = 1; change_state = true; log_printf(TRACE,Load_store_unit,FUNCTION," * rdata_new : 0x%.8x", load_data); } } if (is_big_endian) { // swap in little endian load_data = swapBytes(load_data , _param->_size_general_data>>3,load_size_access); check_hit_byte = swapBits (check_hit_byte, _param->_size_general_data>>3,load_size_access); log_printf(TRACE,Load_store_unit,FUNCTION," * load_data (swap 2) : 0x%.8x",load_data); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit_byte (swap 2) : %x",check_hit_byte); } _load_queue[index_load_queue]._rdata = load_data; _load_queue[index_load_queue]._check_hit_byte = check_hit_byte; _load_queue[index_load_queue]._check_hit = check_hit; log_printf(TRACE,Load_store_unit,FUNCTION," * load_data (after) : 0x%.8x",load_data); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit : %x",check_hit); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit_byte : %x",check_hit_byte); log_printf(TRACE,Load_store_unit,FUNCTION," * mask_end_check : %x",(-1& _param->_mask_address_lsb)); log_printf(TRACE,Load_store_unit,FUNCTION," * mask_check_hit_byte: %x",_param->_mask_check_hit_byte); // The check is finish if all bit is set end_check = (_load_queue[index_load_queue]._check_hit_byte == _param->_mask_check_hit_byte); } } next = true; break; } case STORE_QUEUE_EMPTY : { log_printf(TRACE,Load_store_unit,FUNCTION," * store is empty ... wait."); break; } case STORE_QUEUE_NO_VALID_NO_SPECULATIVE : { log_printf(TRACE,Load_store_unit,FUNCTION," * store have an invalid entry"); if (test_thread_id) { end_check = true; // previous store is invalid -> exception change_state = true; } else next = true; break; } } } if (next) { log_printf(TRACE,Load_store_unit,FUNCTION," * next"); log_printf(TRACE,Load_store_unit,FUNCTION," * new store_queue_ptr_write : %d",store_queue_ptr_write); log_printf(TRACE,Load_store_unit,FUNCTION," * update reg_STORE_QUEUE_NB_CHECK"); #ifdef DEBUG if (reg_STORE_QUEUE_NB_CHECK [store_queue_ptr_write] == 0) throw ERRORMORPHEO(FUNCTION,_("reg_STORE_QUEUE_NB_CHECK must be > 0\n")); #endif reg_STORE_QUEUE_NB_CHECK [store_queue_ptr_write] --; log_printf(TRACE,Load_store_unit,FUNCTION," * reg_STORE_QUEUE_NB_CHECK 1 [%d] <- %d", store_queue_ptr_write,reg_STORE_QUEUE_NB_CHECK [store_queue_ptr_write]); if ((store_queue_ptr_write == store_queue_ptr_read) or (store_queue_ptr_write == reg_STORE_QUEUE_PTR_READ)) { // store_queue_empty = true; end_check = true; change_state = true; } // if (_load_queue[index_load_queue]._store_queue_ptr_write == 0) // _load_queue[index_load_queue]._store_queue_ptr_write = _param->_size_store_queue-1; // else // _load_queue[index_load_queue]._store_queue_ptr_write --; _load_queue[index_load_queue]._store_queue_ptr_write = store_queue_ptr_write; // because the index store have be decrease _load_queue[index_load_queue]._store_queue_empty = store_queue_empty; // because the index store have be decrease // FIXME : peut n'est pas obliger de faire cette comparaison. Au prochain cycle on le détectera que les pointeur sont égaux. Ceci évitera d'avoir deux comparateurs avec le registre "store_queue_ptr_read" } if (change_state) { log_printf(TRACE,Load_store_unit,FUNCTION," * change_state"); log_printf(TRACE,Load_store_unit,FUNCTION," * end_check : %d",end_check); log_printf(TRACE,Load_store_unit,FUNCTION," * state old : %s",toString(_load_queue[index_load_queue]._state).c_str()); switch (_load_queue[index_load_queue]._state) { case LOAD_QUEUE_WAIT_CHECK : { if (end_check) _load_queue[index_load_queue]._state = LOAD_QUEUE_WAIT ; break; } case LOAD_QUEUE_COMMIT_CHECK : { if (end_check) _load_queue[index_load_queue]._state = LOAD_QUEUE_COMMIT; else _load_queue[index_load_queue]._state = LOAD_QUEUE_CHECK; // No commit : check hit and no end break; } case LOAD_QUEUE_CHECK : { if (end_check) _load_queue[index_load_queue]._state = LOAD_QUEUE_COMMIT; // check find a bypass. A speculative load have been committed : report a speculation miss. if ((_load_queue[index_load_queue]._check_hit != 0) and (_load_queue[index_load_queue]._write_rd == 0) // is commit ) { _load_queue[index_load_queue]._exception = EXCEPTION_MEMORY_MISS_SPECULATION; _load_queue[index_load_queue]._write_rd = 1; // write the good result #ifdef STATISTICS if (usage_is_set(_usage,USE_STATISTICS)) (*_stat_nb_inst_load_commit_miss) ++; #endif } break; } default : break; } log_printf(TRACE,Load_store_unit,FUNCTION," * state new : %s",toString(_load_queue[index_load_queue]._state).c_str()); log_printf(TRACE,Load_store_unit,FUNCTION," * exception : %d",_load_queue[index_load_queue]._exception); if (end_check// and not store_queue_empty ) { log_printf(TRACE,Load_store_unit,FUNCTION," * end check, decrease all nb_check"); uint32_t i=store_queue_ptr_write; while (i!=store_queue_ptr_read) { i=((i==0)?_param->_size_store_queue:i)-1; #ifdef DEBUG if (reg_STORE_QUEUE_NB_CHECK [i] == 0) throw ERRORMORPHEO(FUNCTION,_("reg_STORE_QUEUE_NB_CHECK must be > 0\n")); #endif reg_STORE_QUEUE_NB_CHECK [i] --; log_printf(TRACE,Load_store_unit,FUNCTION," * reg_STORE_QUEUE_NB_CHECK 2 [%d] <- %d", i,reg_STORE_QUEUE_NB_CHECK [i]); //i=(i+1)%_param->_size_store_queue; } _load_queue[index_load_queue]._store_queue_empty = true; // end of check } } } // else : don't use a port } //================================================================ // Interface "MEMORY_IN" //================================================================ if ((PORT_READ(in_MEMORY_IN_VAL [internal_MEMORY_IN_PORT]) == 1) and ( internal_MEMORY_IN_ACK == 1)) { log_printf(TRACE,Load_store_unit,FUNCTION," * MEMORY_IN [%d]",internal_MEMORY_IN_PORT); // Test operation : //~~~~~~~~~~~~~~~~~ // store in store_queue // load in speculation_access_queue // others in speculation_access_queue #ifdef DEBUG_TEST if (PORT_READ(in_MEMORY_IN_TYPE [internal_MEMORY_IN_PORT]) != TYPE_MEMORY) throw ERRORMORPHEO(FUNCTION,"The type is different at 'TYPE_MEMORY'"); #endif Toperation_t operation = PORT_READ(in_MEMORY_IN_OPERATION[internal_MEMORY_IN_PORT]); Tcontrol_t cancel = PORT_READ(in_MEMORY_IN_CANCEL [internal_MEMORY_IN_PORT]); Tgeneral_data_t address = (PORT_READ(in_MEMORY_IN_IMMEDIAT[internal_MEMORY_IN_PORT]) + PORT_READ(in_MEMORY_IN_DATA_RA [internal_MEMORY_IN_PORT])); bool exception_alignement = (mask_memory_access(operation) & address) != 0; if (is_operation_memory_store(operation) == true) { // ======================= // ===== STORE_QUEUE ===== // ======================= // There a two store request type : // - first is operation with address and data // - second is the information of re order buffer : the store become not speculative and can access at the data cache log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue"); log_printf(TRACE,Load_store_unit,FUNCTION," * PUSH"); // Write pointer is define in rename stage : Tlsq_ptr_t index = PORT_READ(in_MEMORY_IN_STORE_QUEUE_PTR_WRITE[internal_MEMORY_IN_PORT]); log_printf(TRACE,Load_store_unit,FUNCTION," * index : %d",index); // Need read : state and exception. Tstore_queue_state_t old_state = _store_queue [index]._state; Tstore_queue_state_t new_state = old_state; bool update_info = false; Texception_t old_exception = _store_queue [index]._exception; Texception_t new_exception = old_exception; // Compute next state switch (old_state) { case STORE_QUEUE_EMPTY : { // reg_STORE_QUEUE_INVALID [index] = false; // new first store instruction if (is_operation_memory_store_head(operation) == true) { new_state = STORE_QUEUE_NO_VALID_NO_SPECULATIVE; // test if is a speculation if (operation == OPERATION_MEMORY_STORE_HEAD_KO) { new_exception = EXCEPTION_MEMORY_MISS_SPECULATION; // reg_STORE_QUEUE_INVALID [index] = true; } else new_exception = EXCEPTION_MEMORY_NONE; } else { new_state = STORE_QUEUE_VALID_SPECULATIVE; // Test if have an exception if (exception_alignement == true) new_exception = EXCEPTION_MEMORY_ALIGNMENT; else new_exception = EXCEPTION_MEMORY_NONE; update_info = true; } break; } case STORE_QUEUE_NO_VALID_NO_SPECULATIVE : { #ifdef DEBUG_TEST if (is_operation_memory_store_head(operation) == true) throw ERRORMORPHEO(FUNCTION,_("Transaction in memory_in's interface, actual state of store_queue is \"STORE_QUEUE_NO_VALID_NO_SPECULATIVE\", also a previous store_head have been receiveid. But this operation is a store_head.")); #endif // Test if have a new exception (priority : miss_speculation) if ((exception_alignement == true) and (old_exception == EXCEPTION_MEMORY_NONE)) new_exception = EXCEPTION_MEMORY_ALIGNMENT; if (new_exception != EXCEPTION_MEMORY_NONE) new_state = STORE_QUEUE_COMMIT; else new_state = STORE_QUEUE_VALID_NO_SPECULATIVE; update_info = true; break; } case STORE_QUEUE_VALID_SPECULATIVE : { #ifdef DEBUG_TEST if (is_operation_memory_store_head(operation) == false) throw ERRORMORPHEO(FUNCTION,_("Transaction in memory_in's interface, actual state of store_queue is \"STORE_QUEUE_VALID_SPECULATIVE\", also a previous access with register and address have been receiveid. But this operation is a not store_head.")); #endif if (operation == OPERATION_MEMORY_STORE_HEAD_KO) { new_exception = EXCEPTION_MEMORY_MISS_SPECULATION; // great prioritary // reg_STORE_QUEUE_INVALID [index] = true; } if (new_exception != EXCEPTION_MEMORY_NONE) new_state = STORE_QUEUE_COMMIT; else new_state = STORE_QUEUE_VALID_NO_SPECULATIVE; break; } case STORE_QUEUE_VALID_NO_SPECULATIVE : case STORE_QUEUE_COMMIT : { throw ERRORMORPHEO(FUNCTION," Invalid state and operation"); } } _store_queue [index]._state = new_state; _store_queue [index]._exception = new_exception; if (update_info == true) { log_printf(TRACE,Load_store_unit,FUNCTION," * Update information"); _store_queue [index]._context_id = (not _param->_have_port_context_id )?0:PORT_READ(in_MEMORY_IN_CONTEXT_ID [internal_MEMORY_IN_PORT]); _store_queue [index]._front_end_id = (not _param->_have_port_front_end_id )?0:PORT_READ(in_MEMORY_IN_FRONT_END_ID [internal_MEMORY_IN_PORT]); _store_queue [index]._ooo_engine_id = (not _param->_have_port_ooo_engine_id)?0:PORT_READ(in_MEMORY_IN_OOO_ENGINE_ID[internal_MEMORY_IN_PORT]); _store_queue [index]._packet_id = (not _param->_have_port_rob_ptr )?0:PORT_READ(in_MEMORY_IN_PACKET_ID [internal_MEMORY_IN_PORT]); _store_queue [index]._operation = operation; _store_queue [index]._cancel = cancel ; _store_queue [index]._load_queue_ptr_write = (not _param->_have_port_load_queue_ptr)?0:PORT_READ(in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE[internal_MEMORY_IN_PORT]); _store_queue [index]._address = address; _store_queue [index]._send_commit = false; // reordering data _store_queue [index]._wdata = duplicate(_param->_size_general_data,PORT_READ(in_MEMORY_IN_DATA_RB[internal_MEMORY_IN_PORT]), memory_size(operation), 0); // _store_queue [index]._num_reg_rd = PORT_READ(in_MEMORY_IN_NUM_REG_RD [internal_MEMORY_IN_PORT]); } } else { // ==================================== // ===== SPECULATIVE_ACCESS_QUEUE ===== // ==================================== // In speculative access queue, they are many type's request log_printf(TRACE,Load_store_unit,FUNCTION," * speculative_access_queue"); log_printf(TRACE,Load_store_unit,FUNCTION," * PUSH"); // Write in reservation station uint32_t index = _speculative_access_queue_control->push(); log_printf(TRACE,Load_store_unit,FUNCTION," * index : %d", index); Texception_t exception; if (exception_alignement == true) exception = EXCEPTION_MEMORY_ALIGNMENT; else exception = EXCEPTION_MEMORY_NONE; // if exception, don't access at the cache // NOTE : type "other" (lock, invalidate, flush and sync) can't make an alignement exception (access is equivalent at a 8 bits) _speculative_access_queue [index]._state = (exception == EXCEPTION_MEMORY_NONE)?SPECULATIVE_ACCESS_QUEUE_WAIT_CACHE:SPECULATIVE_ACCESS_QUEUE_WAIT_LOAD_QUEUE; _speculative_access_queue [index]._context_id = (not _param->_have_port_context_id )?0:PORT_READ(in_MEMORY_IN_CONTEXT_ID [internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._front_end_id = (not _param->_have_port_front_end_id )?0:PORT_READ(in_MEMORY_IN_FRONT_END_ID [internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._ooo_engine_id = (not _param->_have_port_ooo_engine_id)?0:PORT_READ(in_MEMORY_IN_OOO_ENGINE_ID[internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._packet_id = (not _param->_have_port_rob_ptr )?0:PORT_READ(in_MEMORY_IN_PACKET_ID [internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._operation = operation; _speculative_access_queue [index]._cancel = cancel ; _speculative_access_queue [index]._load_queue_ptr_write = (not _param->_have_port_load_queue_ptr)?0:PORT_READ(in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE[internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._store_queue_ptr_write= PORT_READ(in_MEMORY_IN_STORE_QUEUE_PTR_WRITE[internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._store_queue_ptr_read = PORT_READ(in_MEMORY_IN_STORE_QUEUE_PTR_READ [internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._store_queue_empty = PORT_READ(in_MEMORY_IN_STORE_QUEUE_EMPTY [internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._address = address; // NOTE : is operation is a load, then they are a result and must write in the register file _speculative_access_queue [index]._write_rd = is_operation_memory_load(operation); _speculative_access_queue [index]._num_reg_rd = PORT_READ(in_MEMORY_IN_NUM_REG_RD [internal_MEMORY_IN_PORT]); _speculative_access_queue [index]._exception = exception; } } //================================================================ // Interface "DCACHE_REQ" //================================================================ if (( internal_DCACHE_REQ_VAL == 1) and (PORT_READ(in_DCACHE_REQ_ACK[0]) == 1)) { log_printf(TRACE,Load_store_unit,FUNCTION," * DCACHE_REQ [0]"); switch (internal_DCACHE_REQ_SELECT_QUEUE) { case SELECT_STORE_QUEUE : { // ======================= // ===== STORE_QUEUE ===== // ======================= // Entry flush and increase the read pointer _store_queue [reg_STORE_QUEUE_PTR_READ]._state = STORE_QUEUE_COMMIT; #if defined(DEBUG) and defined(DEBUG_Load_store_unit) and (DEBUG_Load_store_unit == true) if (log_file_generate) { // log file Tcontext_t num_thread = get_num_thread(_store_queue [reg_STORE_QUEUE_PTR_READ]._context_id , _param->_size_context_id , _store_queue [reg_STORE_QUEUE_PTR_READ]._front_end_id , _param->_size_front_end_id , _store_queue [reg_STORE_QUEUE_PTR_READ]._ooo_engine_id, _param->_size_ooo_engine_id); memory_log_file [num_thread] << "[" << simulation_cycle() << "] " << std::hex << "@ 0x" << std::setfill('0') << std::setw(_param->_size_general_data/4) << _store_queue [reg_STORE_QUEUE_PTR_READ]._address << " -[ Write ]-> 0x" << std::setfill('0') << std::setw(_param->_size_general_data/4) << _store_queue [reg_STORE_QUEUE_PTR_READ]._wdata << " " << std::dec << "{" << toString(_store_queue [reg_STORE_QUEUE_PTR_READ]._operation) << "}"; memory_log_file [num_thread] << std::endl; } #endif break; } case SELECT_LOAD_QUEUE_SPECULATIVE : { // ========================================= // ===== SELECT_LOAD_QUEUE_SPECULATIVE ===== // ========================================= load_queue_push = true; break; } case SELECT_LOAD_QUEUE : { throw ERRORMORPHEO(FUNCTION,_("Invalid selection")); break; } break; } } if (load_queue_push) { log_printf(TRACE,Load_store_unit,FUNCTION," * load_queue_push"); Tlsq_ptr_t ptr_write = _speculative_access_queue[internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._load_queue_ptr_write; Toperation_t operation = _speculative_access_queue[internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._operation; Texception_t exception = _speculative_access_queue[internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._exception; bool have_exception = (exception != EXCEPTION_MEMORY_NONE); bool need_check= false; Tlsq_ptr_t store_queue_ptr_write = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._store_queue_ptr_write; Tlsq_ptr_t store_queue_ptr_read = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._store_queue_ptr_read ; Tcontrol_t store_queue_empty = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._store_queue_empty ; if (have_exception) _load_queue [ptr_write]._state = LOAD_QUEUE_COMMIT; else { if (have_dcache_rsp(operation)) { // load and synchronisation if (must_check(operation) and not store_queue_empty) { // load need_check = true; _load_queue [ptr_write]._state = LOAD_QUEUE_WAIT_CHECK; } else { // synchronisation _load_queue [ptr_write]._state = LOAD_QUEUE_WAIT; } } else { // lock, prefecth, flush and invalidate _load_queue [ptr_write]._state = LOAD_QUEUE_COMMIT; } } Tdcache_address_t address = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._address; Tdcache_address_t address_lsb = (address & _param->_mask_address_lsb); Tdcache_address_t check_hit_byte = gen_mask_not(address_lsb+(memory_size(operation)>>3)-1,address_lsb) & _param->_mask_check_hit_byte; log_printf(TRACE,Load_store_unit,FUNCTION," * address : 0x%.8x", address); log_printf(TRACE,Load_store_unit,FUNCTION," * address_lsb : 0x%.8x", address_lsb); log_printf(TRACE,Load_store_unit,FUNCTION," * operation : %d", operation); log_printf(TRACE,Load_store_unit,FUNCTION," * memory_size : %d", memory_size(operation)); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit_byte : 0x%x", check_hit_byte); _load_queue [ptr_write]._context_id = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._context_id; _load_queue [ptr_write]._front_end_id = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._front_end_id; _load_queue [ptr_write]._ooo_engine_id = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._ooo_engine_id; _load_queue [ptr_write]._packet_id = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._packet_id; _load_queue [ptr_write]._operation = operation; _load_queue [ptr_write]._cancel = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._cancel; _load_queue [ptr_write]._store_queue_ptr_write = store_queue_ptr_write; _load_queue [ptr_write]._store_queue_ptr_read = store_queue_ptr_read ; _load_queue [ptr_write]._store_queue_empty = store_queue_empty ; _load_queue [ptr_write]._address = address; _load_queue [ptr_write]._check_hit_byte = check_hit_byte; _load_queue [ptr_write]._check_hit = 0; _load_queue [ptr_write]._shift = address_lsb<<3;// *8 _load_queue [ptr_write]._is_load_signed = is_operation_memory_load_signed(operation); _load_queue [ptr_write]._access_size = memory_size(operation); // NOTE : if have an exception, must write in register, because a depend instruction wait the load data. _load_queue [ptr_write]._write_rd = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._write_rd ; _load_queue [ptr_write]._num_reg_rd = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._num_reg_rd ; _load_queue [ptr_write]._exception = exception; _load_queue [ptr_write]._rdata = address; // to the exception switch (_param->_speculative_commit_predictor_scheme) { case PREDICTOR_NEVER_TAKE : {_load_queue [ptr_write]._can_speculative_commit = false; break;} case PREDICTOR_ALWAYS_TAKE : {_load_queue [ptr_write]._can_speculative_commit = true ; break;} case PREDICTOR_COUNTER : {_load_queue [ptr_write]._can_speculative_commit = false; break;} // TODO default : { // throw ERRORMORPHEO(FUNCTION,_("Invalid predictor scheme.\n")); _load_queue [ptr_write]._can_speculative_commit = false; break; } } log_printf(TRACE,Load_store_unit,FUNCTION," * speculative_access_queue"); log_printf(TRACE,Load_store_unit,FUNCTION," * POP[%d]",(*_speculative_access_queue_control)[0]); _speculative_access_queue [(*_speculative_access_queue_control)[0]]._state = SPECULATIVE_ACCESS_QUEUE_EMPTY; _speculative_access_queue_control->pop(); #ifdef STATISTICS if (usage_is_set(_usage,USE_STATISTICS)) (*_stat_nb_inst_load) ++; #endif // Only load need check if (need_check// and not store_queue_empty ) // if (is_operation_memory_load(_load_queue [ptr_write]._operation)) { log_printf(TRACE,Load_store_unit,FUNCTION," * update nb_check"); log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_write : %d",store_queue_ptr_write); log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_read : %d",store_queue_ptr_read ); log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_empty : %d",store_queue_empty ); log_printf(TRACE,Load_store_unit,FUNCTION," * reg_STORE_QUEUE_PTR_READ : %d",reg_STORE_QUEUE_PTR_READ); uint32_t i=store_queue_ptr_write; while (i!=store_queue_ptr_read) { i=((i==0)?_param->_size_store_queue:i)-1; log_printf(TRACE,Load_store_unit,FUNCTION," * i : %d",i); reg_STORE_QUEUE_NB_CHECK [i] ++; log_printf(TRACE,Load_store_unit,FUNCTION," * reg_STORE_QUEUE_NB_CHECK 3 [%d] <- %d", i,reg_STORE_QUEUE_NB_CHECK [i]); } } } //================================================================ // Interface "DCACHE_RSP" //================================================================ if ((PORT_READ(in_DCACHE_RSP_VAL[0])== 1) and ( internal_DCACHE_RSP_ACK == 1)) { log_printf(TRACE,Load_store_unit,FUNCTION," * DCACHE_RSP [0]"); // don't use context_id : because there are one queue for all thread //Tcontext_t context_id = PORT_READ(in_DCACHE_RSP_CONTEXT_ID[0]); Tpacket_t packet_id = PORT_READ(in_DCACHE_RSP_PACKET_ID [0]); Tdcache_data_t rdata = PORT_READ(in_DCACHE_RSP_RDATA [0]); Tdcache_error_t error = PORT_READ(in_DCACHE_RSP_ERROR [0]); log_printf(TRACE,Load_store_unit,FUNCTION," * original packet_id : %d" , packet_id); log_printf(TRACE,Load_store_unit,FUNCTION," * packet_id : %d" , packet_id>>1); log_printf(TRACE,Load_store_unit,FUNCTION," * rdata : %.8x", rdata); log_printf(TRACE,Load_store_unit,FUNCTION," * error : %d" , error); if (DCACHE_RSP_IS_LOAD(packet_id) == 1) { packet_id >>= 1; log_printf(TRACE,Load_store_unit,FUNCTION," * packet is a LOAD"); #ifdef DEBUG_TEST if (not have_dcache_rsp(_load_queue [packet_id]._operation)) throw ERRORMORPHEO(FUNCTION,_("Receive of respons, but the corresponding operation don't wait a respons.")); #endif Tdcache_data_t data = _load_queue [packet_id]._rdata; log_printf(TRACE,Load_store_unit,FUNCTION," * data construction"); log_printf(TRACE,Load_store_unit,FUNCTION," * data from cache : 0x%.8x",rdata); log_printf(TRACE,Load_store_unit,FUNCTION," * data (before) : 0x%.8x", data); log_printf(TRACE,Load_store_unit,FUNCTION," * check_hit_byte : 0x%x" ,_load_queue [packet_id]._check_hit_byte); for (uint32_t i=0;i<(_param->_size_general_data>>3)/*8*/; ++i) // Test if this byte has been checked if ((_load_queue [packet_id]._check_hit_byte & (1<(data,rdata,((i+1)<<3)-1,i<<3); } log_printf(TRACE,Load_store_unit,FUNCTION," * data (after) : 0x%.8x", data); _load_queue [packet_id]._rdata = data; #if defined(DEBUG) and defined(DEBUG_Load_store_unit) and (DEBUG_Load_store_unit == true) if (log_file_generate) { // log file Tcontext_t num_thread = get_num_thread(_load_queue [packet_id]._context_id , _param->_size_context_id , _load_queue [packet_id]._front_end_id , _param->_size_front_end_id , _load_queue [packet_id]._ooo_engine_id, _param->_size_ooo_engine_id); memory_log_file [num_thread] << "[" << simulation_cycle() << "] " << std::hex << "@ 0x" << std::setfill('0') << std::setw(_param->_size_general_data/4) << _load_queue [packet_id]._address << " -[ Read ]-> 0x" << std::setfill('0') << std::setw(_param->_size_general_data/4) << _load_queue [packet_id]._rdata << " " << std::dec << "{" << toString(_load_queue [packet_id]._operation) << "}"; memory_log_file [num_thread] << std::endl; } #endif if (error != DCACHE_ERROR_NONE) { log_printf(TRACE,Load_store_unit,FUNCTION," * have a bus error !!!"); _load_queue [packet_id]._exception = EXCEPTION_MEMORY_BUS_ERROR; _load_queue [packet_id]._state = LOAD_QUEUE_COMMIT; log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_write : %d", _load_queue[packet_id]._store_queue_ptr_write); log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_ptr_read : %d", _load_queue[packet_id]._store_queue_ptr_read ); log_printf(TRACE,Load_store_unit,FUNCTION," * store_queue_empty : %d", _load_queue[packet_id]._store_queue_empty ); if (not _load_queue[packet_id]._store_queue_empty) { uint32_t i=_load_queue[packet_id]._store_queue_ptr_write; while (i!=_load_queue[packet_id]._store_queue_ptr_read) { i=((i==0)?_param->_size_store_queue:i)-1; #ifdef DEBUG if (reg_STORE_QUEUE_NB_CHECK [i] == 0) throw ERRORMORPHEO(FUNCTION,_("reg_STORE_QUEUE_NB_CHECK must be > 0\n")); #endif reg_STORE_QUEUE_NB_CHECK [i] --; log_printf(TRACE,Load_store_unit,FUNCTION," * reg_STORE_QUEUE_NB_CHECK 4 [%d] <- %d", i,reg_STORE_QUEUE_NB_CHECK [i]); //i=(i+1)%_param->_size_store_queue; } _load_queue[packet_id]._store_queue_empty = true; // end of check } } else { log_printf(TRACE,Load_store_unit,FUNCTION," * have no bus error."); log_printf(TRACE,Load_store_unit,FUNCTION," * previous state : %s",toString(_load_queue [packet_id]._state).c_str()); // FIXME : convention : if bus error, the cache return the fautive address ! // But, the load's address is aligned ! switch (_load_queue [packet_id]._state) { case LOAD_QUEUE_WAIT_CHECK : _load_queue [packet_id]._state = LOAD_QUEUE_COMMIT_CHECK; break; case LOAD_QUEUE_WAIT : _load_queue [packet_id]._state = LOAD_QUEUE_COMMIT ; break; default : throw ERRORMORPHEO(FUNCTION,_("Illegal state (dcache_rsp).")); break; } } } else { log_printf(TRACE,Load_store_unit,FUNCTION," * packet is a STORE"); // TODO : les stores ne génére pas de réponse sauf quand c'est un bus error !!! throw ERRORMORPHEO(FUNCTION,_("dcache_rsp : no respons to a write. (TODO : manage bus error to the store operation.)")); } } // this register is to manage the priority of check -> Round robin reg_LOAD_QUEUE_CHECK_PRIORITY = (reg_LOAD_QUEUE_CHECK_PRIORITY+1)%_param->_size_load_queue; #if defined(DEBUG) and (DEBUG>=DEBUG_TRACE) // ***** dump store queue log_printf(TRACE,Load_store_unit,FUNCTION," * Dump STORE_QUEUE"); log_printf(TRACE,Load_store_unit,FUNCTION," * ptr_read : %d",reg_STORE_QUEUE_PTR_READ); for (uint32_t i=0; i<_param->_size_store_queue; i++) { uint32_t j = (reg_STORE_QUEUE_PTR_READ+i)%_param->_size_store_queue; log_printf(TRACE,Load_store_unit,FUNCTION," [%.4d] %.4d %.4d %.4d, %.4d, %.4d %.1d, %.4d, %.8x %.8x, %.2d %.1d, %.2d %s", j, _store_queue[j]._context_id , _store_queue[j]._front_end_id , _store_queue[j]._ooo_engine_id , _store_queue[j]._packet_id , _store_queue[j]._operation , _store_queue[j]._cancel , _store_queue[j]._load_queue_ptr_write, _store_queue[j]._address , _store_queue[j]._wdata , //_store_queue[j]._write_rd , //_store_queue[j]._num_reg_rd , _store_queue[j]._exception , _store_queue[j]._send_commit , reg_STORE_QUEUE_NB_CHECK [j] , toString(_store_queue[j]._state).c_str()); } // ***** dump speculative_access queue log_printf(TRACE,Load_store_unit,FUNCTION," * Dump SPECULATIVE_ACCESS_QUEUE"); for (uint32_t i=0; i<_param->_size_speculative_access_queue; i++) { uint32_t j = (*_speculative_access_queue_control)[i]; log_printf(TRACE,Load_store_unit,FUNCTION," [%.4d] %.4d %.4d %.4d, %.4d, %.4d %.1d, %.4d %.4d %.4d %.1d, %.8x, %.1d %.4d, %.2d, %s", j, _speculative_access_queue[j]._context_id , _speculative_access_queue[j]._front_end_id , _speculative_access_queue[j]._ooo_engine_id , _speculative_access_queue[j]._packet_id , _speculative_access_queue[j]._operation , _speculative_access_queue[j]._cancel , _speculative_access_queue[j]._load_queue_ptr_write, _speculative_access_queue[j]._store_queue_ptr_write, _speculative_access_queue[j]._store_queue_ptr_read , _speculative_access_queue[j]._store_queue_empty , _speculative_access_queue[j]._address , _speculative_access_queue[j]._write_rd , _speculative_access_queue[j]._num_reg_rd , _speculative_access_queue[j]._exception , toString(_speculative_access_queue[j]._state).c_str()); } // ***** dump load queue log_printf(TRACE,Load_store_unit,FUNCTION," * Dump LOAD_QUEUE"); log_printf(TRACE,Load_store_unit,FUNCTION," * ptr_read_check_priority : %d",reg_LOAD_QUEUE_CHECK_PRIORITY); for (uint32_t i=0; i<_param->_size_load_queue; i++) { uint32_t j = i; log_printf(TRACE,Load_store_unit,FUNCTION," [%.4d] %.4d %.4d %.4d, %.4d, %.4d %.1d, %.4d %.4d %.1d, %.8x %.1x %.1d %.2d %.1d %.2d, %.8x, %.1d %.4d, %.2d, %s", j, _load_queue[j]._context_id , _load_queue[j]._front_end_id , _load_queue[j]._ooo_engine_id , _load_queue[j]._packet_id , _load_queue[j]._operation , _load_queue[j]._cancel , _load_queue[j]._store_queue_ptr_write, _load_queue[j]._store_queue_ptr_read , _load_queue[j]._store_queue_empty , _load_queue[j]._address , _load_queue[j]._check_hit_byte , _load_queue[j]._check_hit , _load_queue[j]._shift , _load_queue[j]._is_load_signed , _load_queue[j]._access_size , _load_queue[j]._rdata , _load_queue[j]._write_rd , _load_queue[j]._num_reg_rd , _load_queue[j]._exception , toString(_load_queue[j]._state).c_str()); } #endif #ifdef STATISTICS if (usage_is_set(_usage,USE_STATISTICS)) { for (uint32_t i=0; i<_param->_size_store_queue; i++) if (_store_queue[i]._state != STORE_QUEUE_EMPTY) (*_stat_use_store_queue) ++; for (uint32_t i=0; i<_param->_size_speculative_access_queue; i++) if (_speculative_access_queue[i]._state != SPECULATIVE_ACCESS_QUEUE_EMPTY) (*_stat_use_speculative_access_queue) ++; for (uint32_t i=0; i<_param->_size_load_queue; i++) if (_load_queue[i]._state != LOAD_QUEUE_EMPTY) (*_stat_use_load_queue) ++; } #endif } log_end(Load_store_unit,FUNCTION); }; }; // end namespace load_store_unit }; // end namespace execute_unit }; // end namespace multi_execute_unit }; // end namespace execute_loop }; // end namespace multi_execute_loop }; // end namespace core }; // end namespace behavioural }; // end namespace morpheo #endif