386 | | // XMIN(5 bits) / XMAX(5 bits) / YMIN(5 bits) / YMAX(5 bits) |
387 | | // 0b00000 / 0b11111 / 0b00000 / 0b11111 |
388 | | m_broadcast_boundaries(0x7C1F), |
389 | | |
390 | | |
391 | | // FIFOs |
392 | | m_cmd_read_addr_fifo("m_cmd_read_addr_fifo", 4), |
393 | | m_cmd_read_length_fifo("m_cmd_read_length_fifo", 4), |
394 | | m_cmd_read_srcid_fifo("m_cmd_read_srcid_fifo", 4), |
395 | | m_cmd_read_trdid_fifo("m_cmd_read_trdid_fifo", 4), |
396 | | m_cmd_read_pktid_fifo("m_cmd_read_pktid_fifo", 4), |
397 | | |
398 | | m_cmd_write_addr_fifo("m_cmd_write_addr_fifo",8), |
399 | | m_cmd_write_eop_fifo("m_cmd_write_eop_fifo",8), |
400 | | m_cmd_write_srcid_fifo("m_cmd_write_srcid_fifo",8), |
401 | | m_cmd_write_trdid_fifo("m_cmd_write_trdid_fifo",8), |
402 | | m_cmd_write_pktid_fifo("m_cmd_write_pktid_fifo",8), |
403 | | m_cmd_write_data_fifo("m_cmd_write_data_fifo",8), |
404 | | m_cmd_write_be_fifo("m_cmd_write_be_fifo",8), |
405 | | |
406 | | m_cmd_cas_addr_fifo("m_cmd_cas_addr_fifo",4), |
407 | | m_cmd_cas_eop_fifo("m_cmd_cas_eop_fifo",4), |
408 | | m_cmd_cas_srcid_fifo("m_cmd_cas_srcid_fifo",4), |
409 | | m_cmd_cas_trdid_fifo("m_cmd_cas_trdid_fifo",4), |
410 | | m_cmd_cas_pktid_fifo("m_cmd_cas_pktid_fifo",4), |
411 | | m_cmd_cas_wdata_fifo("m_cmd_cas_wdata_fifo",4), |
412 | | |
413 | | m_cc_receive_to_cleanup_fifo("m_cc_receive_to_cleanup_fifo", 4), |
414 | | m_cc_receive_to_multi_ack_fifo("m_cc_receive_to_multi_ack_fifo", 4), |
415 | | |
416 | | r_tgt_cmd_fsm("r_tgt_cmd_fsm"), |
417 | | |
418 | | r_config_fsm( "r_config_fsm" ), |
419 | | |
420 | | m_config_to_cc_send_inst_fifo( "m_config_to_cc_send_inst_fifo", 8 ), |
421 | | m_config_to_cc_send_srcid_fifo( "m_config_to_cc_send_srcid_fifo", 8 ), |
422 | | |
423 | | r_read_fsm( "r_read_fsm" ), |
424 | | |
425 | | r_write_fsm( "r_write_fsm" ), |
426 | | |
427 | | m_write_to_cc_send_inst_fifo("m_write_to_cc_send_inst_fifo",8), |
428 | | m_write_to_cc_send_srcid_fifo("m_write_to_cc_send_srcid_fifo",8), |
429 | | |
430 | | r_multi_ack_fsm("r_multi_ack_fsm"), |
431 | | |
432 | | r_cleanup_fsm("r_cleanup_fsm"), |
433 | | |
434 | | r_cas_fsm("r_cas_fsm"), |
435 | | |
436 | | m_cas_to_cc_send_inst_fifo("m_cas_to_cc_send_inst_fifo",8), |
437 | | m_cas_to_cc_send_srcid_fifo("m_cas_to_cc_send_srcid_fifo",8), |
438 | | |
439 | | r_ixr_rsp_fsm("r_ixr_rsp_fsm"), |
440 | | r_xram_rsp_fsm("r_xram_rsp_fsm"), |
441 | | |
442 | | m_xram_rsp_to_cc_send_inst_fifo("m_xram_rsp_to_cc_send_inst_fifo",8), |
443 | | m_xram_rsp_to_cc_send_srcid_fifo("m_xram_rsp_to_cc_send_srcid_fifo",8), |
444 | | |
445 | | r_ixr_cmd_fsm("r_ixr_cmd_fsm"), |
446 | | |
447 | | r_tgt_rsp_fsm("r_tgt_rsp_fsm"), |
448 | | |
449 | | r_cc_send_fsm("r_cc_send_fsm"), |
450 | | r_cc_receive_fsm("r_cc_receive_fsm"), |
451 | | |
452 | | r_alloc_dir_fsm("r_alloc_dir_fsm"), |
453 | | r_alloc_dir_reset_cpt("r_alloc_dir_reset_cpt"), |
454 | | r_alloc_trt_fsm("r_alloc_trt_fsm"), |
455 | | r_alloc_upt_fsm("r_alloc_upt_fsm"), |
456 | | r_alloc_ivt_fsm("r_alloc_ivt_fsm"), |
457 | | r_alloc_heap_fsm("r_alloc_heap_fsm"), |
458 | | r_alloc_heap_reset_cpt("r_alloc_heap_reset_cpt") |
459 | | { |
460 | | std::cout << " - Building VciMemCache : " << name << std::endl; |
461 | | |
462 | | assert(IS_POW_OF_2(nsets)); |
463 | | assert(IS_POW_OF_2(nwords)); |
464 | | assert(IS_POW_OF_2(nways)); |
465 | | assert(nsets); |
466 | | assert(nwords); |
467 | | assert(nways); |
468 | | |
469 | | // check Transaction table size |
470 | | assert((uint32_log2(trt_lines) <= vci_param_ext::T) and |
471 | | "MEMC ERROR : Need more bits for VCI TRDID field"); |
472 | | |
473 | | // check internal and external data width |
474 | | assert( (vci_param_int::B == 4 ) and |
475 | | "MEMC ERROR : VCI internal data width must be 32 bits"); |
476 | | |
477 | | assert( (vci_param_ext::B == 8) and |
478 | | "MEMC ERROR : VCI external data width must be 64 bits"); |
479 | | |
480 | | // Check coherence between internal & external addresses |
481 | | assert( (vci_param_int::N == vci_param_ext::N) and |
482 | | "MEMC ERROR : VCI internal & external addresses must have the same width"); |
483 | | |
484 | | // Get the segments associated to the MemCache |
485 | | std::list<soclib::common::Segment>::iterator seg; |
486 | | size_t i = 0; |
487 | | |
488 | | for(seg = m_seglist.begin(); seg != m_seglist.end() ; seg++) |
| 390 | // XMIN(5 bits) / XMAX(5 bits) / YMIN(5 bits) / YMAX(5 bits) |
| 391 | // 0b00000 / 0b11111 / 0b00000 / 0b11111 |
| 392 | m_broadcast_boundaries(0x7C1F), |
| 393 | |
| 394 | |
| 395 | // FIFOs |
| 396 | m_cmd_read_addr_fifo("m_cmd_read_addr_fifo", 4), |
| 397 | m_cmd_read_length_fifo("m_cmd_read_length_fifo", 4), |
| 398 | m_cmd_read_srcid_fifo("m_cmd_read_srcid_fifo", 4), |
| 399 | m_cmd_read_trdid_fifo("m_cmd_read_trdid_fifo", 4), |
| 400 | m_cmd_read_pktid_fifo("m_cmd_read_pktid_fifo", 4), |
| 401 | |
| 402 | m_cmd_write_addr_fifo("m_cmd_write_addr_fifo",8), |
| 403 | m_cmd_write_eop_fifo("m_cmd_write_eop_fifo",8), |
| 404 | m_cmd_write_srcid_fifo("m_cmd_write_srcid_fifo",8), |
| 405 | m_cmd_write_trdid_fifo("m_cmd_write_trdid_fifo",8), |
| 406 | m_cmd_write_pktid_fifo("m_cmd_write_pktid_fifo",8), |
| 407 | m_cmd_write_data_fifo("m_cmd_write_data_fifo",8), |
| 408 | m_cmd_write_be_fifo("m_cmd_write_be_fifo",8), |
| 409 | |
| 410 | m_cmd_cas_addr_fifo("m_cmd_cas_addr_fifo",4), |
| 411 | m_cmd_cas_eop_fifo("m_cmd_cas_eop_fifo",4), |
| 412 | m_cmd_cas_srcid_fifo("m_cmd_cas_srcid_fifo",4), |
| 413 | m_cmd_cas_trdid_fifo("m_cmd_cas_trdid_fifo",4), |
| 414 | m_cmd_cas_pktid_fifo("m_cmd_cas_pktid_fifo",4), |
| 415 | m_cmd_cas_wdata_fifo("m_cmd_cas_wdata_fifo",4), |
| 416 | |
| 417 | m_cc_receive_to_cleanup_fifo("m_cc_receive_to_cleanup_fifo", 4), |
| 418 | m_cc_receive_to_multi_ack_fifo("m_cc_receive_to_multi_ack_fifo", 4), |
| 419 | |
| 420 | r_tgt_cmd_fsm("r_tgt_cmd_fsm"), |
| 421 | |
| 422 | r_config_fsm( "r_config_fsm" ), |
| 423 | |
| 424 | m_config_to_cc_send_inst_fifo( "m_config_to_cc_send_inst_fifo", 8 ), |
| 425 | m_config_to_cc_send_srcid_fifo( "m_config_to_cc_send_srcid_fifo", 8 ), |
| 426 | |
| 427 | r_read_fsm( "r_read_fsm" ), |
| 428 | |
| 429 | r_write_fsm( "r_write_fsm" ), |
| 430 | |
| 431 | m_write_to_cc_send_inst_fifo("m_write_to_cc_send_inst_fifo",8), |
| 432 | m_write_to_cc_send_srcid_fifo("m_write_to_cc_send_srcid_fifo",8), |
| 433 | |
| 434 | r_multi_ack_fsm("r_multi_ack_fsm"), |
| 435 | |
| 436 | r_cleanup_fsm("r_cleanup_fsm"), |
| 437 | |
| 438 | r_cas_fsm("r_cas_fsm"), |
| 439 | |
| 440 | m_cas_to_cc_send_inst_fifo("m_cas_to_cc_send_inst_fifo",8), |
| 441 | m_cas_to_cc_send_srcid_fifo("m_cas_to_cc_send_srcid_fifo",8), |
| 442 | |
| 443 | r_ixr_rsp_fsm("r_ixr_rsp_fsm"), |
| 444 | r_xram_rsp_fsm("r_xram_rsp_fsm"), |
| 445 | |
| 446 | m_xram_rsp_to_cc_send_inst_fifo("m_xram_rsp_to_cc_send_inst_fifo",8), |
| 447 | m_xram_rsp_to_cc_send_srcid_fifo("m_xram_rsp_to_cc_send_srcid_fifo",8), |
| 448 | |
| 449 | r_ixr_cmd_fsm("r_ixr_cmd_fsm"), |
| 450 | |
| 451 | r_tgt_rsp_fsm("r_tgt_rsp_fsm"), |
| 452 | |
| 453 | r_cc_send_fsm("r_cc_send_fsm"), |
| 454 | r_cc_receive_fsm("r_cc_receive_fsm"), |
| 455 | |
| 456 | r_alloc_dir_fsm("r_alloc_dir_fsm"), |
| 457 | r_alloc_dir_reset_cpt("r_alloc_dir_reset_cpt"), |
| 458 | r_alloc_trt_fsm("r_alloc_trt_fsm"), |
| 459 | r_alloc_upt_fsm("r_alloc_upt_fsm"), |
| 460 | r_alloc_ivt_fsm("r_alloc_ivt_fsm"), |
| 461 | r_alloc_heap_fsm("r_alloc_heap_fsm"), |
| 462 | r_alloc_heap_reset_cpt("r_alloc_heap_reset_cpt") |
| 463 | { |
| 464 | std::cout << " - Building VciMemCache : " << name << std::endl; |
| 465 | |
| 466 | assert(IS_POW_OF_2(nsets)); |
| 467 | assert(IS_POW_OF_2(nwords)); |
| 468 | assert(IS_POW_OF_2(nways)); |
| 469 | assert(nsets); |
| 470 | assert(nwords); |
| 471 | assert(nways); |
| 472 | |
| 473 | // check Transaction table size |
| 474 | assert((uint32_log2(trt_lines) <= vci_param_ext::T) and |
| 475 | "MEMC ERROR : Need more bits for VCI TRDID field"); |
| 476 | |
| 477 | // check internal and external data width |
| 478 | assert( (vci_param_int::B == 4 ) and |
| 479 | "MEMC ERROR : VCI internal data width must be 32 bits"); |
| 480 | |
| 481 | assert( (vci_param_ext::B == 8) and |
| 482 | "MEMC ERROR : VCI external data width must be 64 bits"); |
| 483 | |
| 484 | // Check coherence between internal & external addresses |
| 485 | assert( (vci_param_int::N == vci_param_ext::N) and |
| 486 | "MEMC ERROR : VCI internal & external addresses must have the same width"); |
| 487 | |
| 488 | // Get the segments associated to the MemCache |
| 489 | std::list<soclib::common::Segment>::iterator seg; |
| 490 | size_t i = 0; |
| 491 | |
| 492 | for (seg = m_seglist.begin(); seg != m_seglist.end(); seg++) |
| 493 | { |
| 494 | std::cout << " => segment " << seg->name() |
| 495 | << " / base = " << std::hex << seg->baseAddress() |
| 496 | << " / size = " << seg->size() << std::endl; |
| 497 | m_nseg++; |
| 498 | } |
| 499 | |
| 500 | m_seg = new soclib::common::Segment*[m_nseg]; |
| 501 | |
| 502 | for (seg = m_seglist.begin(); seg != m_seglist.end(); seg++) |
| 503 | { |
| 504 | if (seg->special() ) m_seg_config = i; |
| 505 | m_seg[i] = & (*seg); |
| 506 | i++; |
| 507 | } |
| 508 | |
| 509 | // Allocation for IXR_RSP FSM |
| 510 | r_ixr_rsp_to_xram_rsp_rok = new sc_signal<bool>[m_trt_lines]; |
| 511 | |
| 512 | // Allocation for XRAM_RSP FSM |
| 513 | r_xram_rsp_victim_data = new sc_signal<data_t>[nwords]; |
| 514 | r_xram_rsp_to_tgt_rsp_data = new sc_signal<data_t>[nwords]; |
| 515 | |
| 516 | // Allocation for READ FSM |
| 517 | r_read_data = new sc_signal<data_t>[nwords]; |
| 518 | r_read_to_tgt_rsp_data = new sc_signal<data_t>[nwords]; |
| 519 | |
| 520 | // Allocation for WRITE FSM |
| 521 | r_write_data = new sc_signal<data_t>[nwords]; |
| 522 | r_write_be = new sc_signal<be_t>[nwords]; |
| 523 | r_write_to_cc_send_data = new sc_signal<data_t>[nwords]; |
| 524 | r_write_to_cc_send_be = new sc_signal<be_t>[nwords]; |
| 525 | |
| 526 | // Allocation for CAS FSM |
| 527 | r_cas_data = new sc_signal<data_t>[nwords]; |
| 528 | r_cas_rdata = new sc_signal<data_t>[2]; |
| 529 | |
| 530 | // Allocation for IXR_CMD FSM |
| 531 | r_ixr_cmd_wdata = new sc_signal<data_t>[nwords]; |
| 532 | |
| 533 | // Allocation for debug |
| 534 | m_debug_previous_data = new data_t[nwords]; |
| 535 | m_debug_data = new data_t[nwords]; |
| 536 | |
| 537 | SC_METHOD(transition); |
| 538 | dont_initialize(); |
| 539 | sensitive << p_clk.pos(); |
| 540 | |
| 541 | SC_METHOD(genMoore); |
| 542 | dont_initialize(); |
| 543 | sensitive << p_clk.neg(); |
| 544 | } // end constructor |
| 545 | |
| 546 | |
| 547 | ///////////////////////////////////////////////////// |
| 548 | tmpl(void) ::cache_monitor(addr_t addr) |
| 549 | ///////////////////////////////////////////////////// |
1019 | | if(m_debug) |
1020 | | std::cout << " <MEMC " << name() |
1021 | | << " TGT_CMD_ERROR> Segmentation violation:" |
1022 | | << " address = " << std::hex << p_vci_tgt.address.read() |
1023 | | << " / srcid = " << p_vci_tgt.srcid.read() |
1024 | | << " / trdid = " << p_vci_tgt.trdid.read() |
1025 | | << " / pktid = " << p_vci_tgt.pktid.read() |
1026 | | << " / plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
1027 | | #endif |
1028 | | |
1029 | | } |
1030 | | break; |
1031 | | |
1032 | | //////////////////// |
1033 | | case TGT_CMD_CONFIG: // execute config request and return response |
1034 | | { |
1035 | | addr_t seg_base = m_seg[m_seg_config]->baseAddress(); |
1036 | | addr_t address = p_vci_tgt.address.read(); |
1037 | | size_t cell = (address - seg_base)/vci_param_int::B; |
1038 | | |
1039 | | bool need_rsp; |
1040 | | size_t error; |
1041 | | uint32_t rdata = 0; // default value |
1042 | | uint32_t wdata = p_vci_tgt.wdata.read(); |
1043 | | |
1044 | | if ( (p_vci_tgt.cmd.read() == vci_param_int::CMD_READ) // get lock |
1045 | | and (cell == MEMC_LOCK) ) |
| 1046 | if (m_debug) |
| 1047 | std::cout << " <MEMC " << name() |
| 1048 | << " TGT_CMD_IDLE> Receive command from srcid " |
| 1049 | << std::hex << p_vci_tgt.srcid.read() |
| 1050 | << " / address " << std::hex << p_vci_tgt.address.read() << std::endl; |
| 1051 | #endif |
| 1052 | // checking segmentation violation |
| 1053 | addr_t address = p_vci_tgt.address.read(); |
| 1054 | uint32_t plen = p_vci_tgt.plen.read(); |
| 1055 | bool found = false; |
| 1056 | bool config = false; |
| 1057 | |
| 1058 | for (size_t seg_id = 0; (seg_id < m_nseg) && !found; seg_id++) |
| 1059 | { |
| 1060 | if (m_seg[seg_id]->contains(address) && |
| 1061 | m_seg[seg_id]->contains(address + plen - vci_param_int::B)) |
| 1062 | { |
| 1063 | found = true; |
| 1064 | if (m_seg[seg_id]->special()) config = true; |
| 1065 | } |
| 1066 | } |
| 1067 | |
| 1068 | if (!found) /////////// out of segment error |
| 1069 | { |
| 1070 | r_tgt_cmd_fsm = TGT_CMD_ERROR; |
| 1071 | } |
| 1072 | else if (config) /////////// configuration command |
| 1073 | { |
| 1074 | if (!p_vci_tgt.eop.read()) r_tgt_cmd_fsm = TGT_CMD_ERROR; |
| 1075 | else r_tgt_cmd_fsm = TGT_CMD_CONFIG; |
| 1076 | } |
| 1077 | else //////////// memory access |
| 1078 | { |
| 1079 | if (p_vci_tgt.cmd.read() == vci_param_int::CMD_READ) |
| 1080 | { |
| 1081 | // check that the pktid is either : |
| 1082 | // TYPE_READ_DATA_UNC |
| 1083 | // TYPE_READ_DATA_MISS |
| 1084 | // TYPE_READ_INS_UNC |
| 1085 | // TYPE_READ_INS_MISS |
| 1086 | // ==> bit2 must be zero with the TSAR encoding |
| 1087 | // ==> mask = 0b0100 = 0x4 |
| 1088 | assert(((p_vci_tgt.pktid.read() & 0x4) == 0x0) and |
| 1089 | "The type specified in the pktid field is incompatible with the READ CMD"); |
| 1090 | r_tgt_cmd_fsm = TGT_CMD_READ; |
| 1091 | } |
| 1092 | else if (p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) |
| 1093 | { |
| 1094 | // check that the pktid is TYPE_WRITE |
| 1095 | // ==> TYPE_WRITE = X100 with the TSAR encoding |
| 1096 | // ==> mask = 0b0111 = 0x7 |
| 1097 | assert(((p_vci_tgt.pktid.read() & 0x7) == 0x4) and |
| 1098 | "The type specified in the pktid field is incompatible with the WRITE CMD"); |
| 1099 | r_tgt_cmd_fsm = TGT_CMD_WRITE; |
| 1100 | } |
| 1101 | else if (p_vci_tgt.cmd.read() == vci_param_int::CMD_LOCKED_READ) |
| 1102 | { |
| 1103 | // check that the pktid is TYPE_LL |
| 1104 | // ==> TYPE_LL = X110 with the TSAR encoding |
| 1105 | // ==> mask = 0b0111 = 0x7 |
| 1106 | assert(((p_vci_tgt.pktid.read() & 0x7) == 0x6) and |
| 1107 | "The type specified in the pktid field is incompatible with the LL CMD"); |
| 1108 | r_tgt_cmd_fsm = TGT_CMD_READ; |
| 1109 | } |
| 1110 | else if (p_vci_tgt.cmd.read() == vci_param_int::CMD_NOP) |
| 1111 | { |
| 1112 | // check that the pktid is either : |
| 1113 | // TYPE_CAS |
| 1114 | // TYPE_SC |
| 1115 | // ==> TYPE_CAS = X101 with the TSAR encoding |
| 1116 | // ==> TYPE_SC = X111 with the TSAR encoding |
| 1117 | // ==> mask = 0b0101 = 0x5 |
| 1118 | assert(((p_vci_tgt.pktid.read() & 0x5) == 0x5) and |
| 1119 | "The type specified in the pktid field is incompatible with the NOP CMD"); |
| 1120 | |
| 1121 | if ((p_vci_tgt.pktid.read() & 0x7) == TYPE_CAS) r_tgt_cmd_fsm = TGT_CMD_CAS; |
| 1122 | else r_tgt_cmd_fsm = TGT_CMD_WRITE; |
| 1123 | } |
| 1124 | else |
| 1125 | { |
| 1126 | r_tgt_cmd_fsm = TGT_CMD_ERROR; |
| 1127 | } |
| 1128 | } |
| 1129 | } |
| 1130 | break; |
| 1131 | |
| 1132 | /////////////////// |
| 1133 | case TGT_CMD_ERROR: // response error must be sent |
| 1134 | |
| 1135 | // wait if pending request |
| 1136 | if (r_tgt_cmd_to_tgt_rsp_req.read()) break; |
| 1137 | |
| 1138 | // consume all the command packet flits before sending response error |
| 1139 | if (p_vci_tgt.cmdval and p_vci_tgt.eop) |
| 1140 | { |
| 1141 | r_tgt_cmd_to_tgt_rsp_srcid = p_vci_tgt.srcid.read(); |
| 1142 | r_tgt_cmd_to_tgt_rsp_trdid = p_vci_tgt.trdid.read(); |
| 1143 | r_tgt_cmd_to_tgt_rsp_pktid = p_vci_tgt.pktid.read(); |
| 1144 | r_tgt_cmd_to_tgt_rsp_req = true; |
| 1145 | r_tgt_cmd_to_tgt_rsp_error = 1; |
| 1146 | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
| 1147 | |
| 1148 | #if DEBUG_MEMC_TGT_CMD |
| 1149 | if (m_debug) |
| 1150 | std::cout << " <MEMC " << name() |
| 1151 | << " TGT_CMD_ERROR> Segmentation violation:" |
| 1152 | << " address = " << std::hex << p_vci_tgt.address.read() |
| 1153 | << " / srcid = " << p_vci_tgt.srcid.read() |
| 1154 | << " / trdid = " << p_vci_tgt.trdid.read() |
| 1155 | << " / pktid = " << p_vci_tgt.pktid.read() |
| 1156 | << " / plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
| 1157 | #endif |
| 1158 | |
| 1159 | } |
| 1160 | break; |
| 1161 | |
| 1162 | //////////////////// |
| 1163 | case TGT_CMD_CONFIG: // execute config request and return response |
| 1164 | { |
| 1165 | addr_t seg_base = m_seg[m_seg_config]->baseAddress(); |
| 1166 | addr_t address = p_vci_tgt.address.read(); |
| 1167 | size_t cell = (address - seg_base) / vci_param_int::B; |
| 1168 | |
| 1169 | bool need_rsp; |
| 1170 | size_t error; |
| 1171 | uint32_t rdata = 0; // default value |
| 1172 | uint32_t wdata = p_vci_tgt.wdata.read(); |
| 1173 | |
| 1174 | if ((p_vci_tgt.cmd.read() == vci_param_int::CMD_READ) // get lock |
| 1175 | and (cell == MEMC_LOCK)) |
| 1176 | { |
| 1177 | rdata = (uint32_t) r_config_lock.read(); |
| 1178 | need_rsp = true; |
| 1179 | error = 0; |
| 1180 | r_config_lock = true; |
| 1181 | if (rdata == 0) |
| 1182 | { |
| 1183 | r_tgt_cmd_srcid = p_vci_tgt.srcid.read(); |
| 1184 | r_tgt_cmd_trdid = p_vci_tgt.trdid.read(); |
| 1185 | r_tgt_cmd_pktid = p_vci_tgt.pktid.read(); |
| 1186 | } |
| 1187 | } |
| 1188 | else if ((p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // release lock |
| 1189 | and (cell == MEMC_LOCK)) |
| 1190 | { |
| 1191 | need_rsp = true; |
| 1192 | error = 0; |
| 1193 | r_config_lock = false; |
| 1194 | } |
| 1195 | else if ((p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set addr_lo |
| 1196 | and (cell == MEMC_ADDR_LO)) |
| 1197 | { |
| 1198 | assert( ((wdata % (m_words * vci_param_int::B)) == 0) and |
| 1199 | "VCI_MEM_CACHE CONFIG ERROR: The buffer must be aligned on a cache line"); |
| 1200 | |
| 1201 | need_rsp = true; |
| 1202 | error = 0; |
| 1203 | r_config_address = (r_config_address.read() & 0xFFFFFFFF00000000LL) | |
| 1204 | ((addr_t)wdata); |
| 1205 | } |
| 1206 | else if ((p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set addr_hi |
| 1207 | and (cell == MEMC_ADDR_HI)) |
| 1208 | |
| 1209 | { |
| 1210 | need_rsp = true; |
| 1211 | error = 0; |
| 1212 | r_config_address = (r_config_address.read() & 0x00000000FFFFFFFFLL) | |
| 1213 | (((addr_t) wdata) << 32); |
| 1214 | } |
| 1215 | else if ((p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set buf_lines |
| 1216 | and (cell == MEMC_BUF_LENGTH)) |
| 1217 | { |
| 1218 | need_rsp = true; |
| 1219 | error = 0; |
| 1220 | size_t lines = wdata / (m_words << 2); |
| 1221 | if (wdata % (m_words << 2)) lines++; |
| 1222 | r_config_cmd_lines = lines; |
| 1223 | r_config_rsp_lines = lines; |
| 1224 | } |
| 1225 | else if ((p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set cmd type |
| 1226 | and (cell == MEMC_CMD_TYPE)) |
| 1227 | { |
| 1228 | need_rsp = false; |
| 1229 | error = 0; |
| 1230 | r_config_cmd = wdata; |
| 1231 | |
| 1232 | // prepare delayed response from CONFIG FSM |
| 1233 | r_config_srcid = p_vci_tgt.srcid.read(); |
| 1234 | r_config_trdid = p_vci_tgt.trdid.read(); |
| 1235 | r_config_pktid = p_vci_tgt.pktid.read(); |
| 1236 | } |
| 1237 | else |
| 1238 | { |
| 1239 | need_rsp = true; |
| 1240 | error = 1; |
| 1241 | } |
| 1242 | |
| 1243 | if (need_rsp) |
| 1244 | { |
| 1245 | // blocked if previous pending request to TGT_RSP FSM |
| 1246 | if (r_tgt_cmd_to_tgt_rsp_req.read()) break; |
| 1247 | |
| 1248 | r_tgt_cmd_to_tgt_rsp_srcid = p_vci_tgt.srcid.read(); |
| 1249 | r_tgt_cmd_to_tgt_rsp_trdid = p_vci_tgt.trdid.read(); |
| 1250 | r_tgt_cmd_to_tgt_rsp_pktid = p_vci_tgt.pktid.read(); |
| 1251 | r_tgt_cmd_to_tgt_rsp_req = true; |
| 1252 | r_tgt_cmd_to_tgt_rsp_error = error; |
| 1253 | r_tgt_cmd_to_tgt_rsp_rdata = rdata; |
| 1254 | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
| 1255 | } |
| 1256 | else |
| 1257 | { |
| 1258 | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
| 1259 | } |
| 1260 | |
| 1261 | #if DEBUG_MEMC_TGT_CMD |
| 1262 | if (m_debug) |
| 1263 | std::cout << " <MEMC " << name() << " TGT_CMD_CONFIG> Configuration request:" |
| 1264 | << " address = " << std::hex << p_vci_tgt.address.read() |
| 1265 | << " / wdata = " << p_vci_tgt.wdata.read() |
| 1266 | << " / need_rsp = " << need_rsp |
| 1267 | << " / error = " << error << std::endl; |
| 1268 | #endif |
| 1269 | break; |
| 1270 | } |
| 1271 | ////////////////// |
| 1272 | case TGT_CMD_READ: // Push a read request into read fifo |
| 1273 | |
| 1274 | // check that the read does not cross a cache line limit. |
| 1275 | if (((m_x[(addr_t) p_vci_tgt.address.read()] + (p_vci_tgt.plen.read() >> 2)) > 16) and |
| 1276 | (p_vci_tgt.cmd.read() != vci_param_int::CMD_LOCKED_READ)) |
| 1277 | { |
| 1278 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" |
| 1279 | << " illegal address/plen for VCI read command" << std::endl; |
| 1280 | exit(0); |
| 1281 | } |
| 1282 | // check single flit |
| 1283 | if (!p_vci_tgt.eop.read()) |
| 1284 | { |
| 1285 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" |
| 1286 | << " read command packet must contain one single flit" << std::endl; |
| 1287 | exit(0); |
| 1288 | } |
| 1289 | // check plen for LL |
| 1290 | if ((p_vci_tgt.cmd.read() == vci_param_int::CMD_LOCKED_READ) and |
| 1291 | (p_vci_tgt.plen.read() != 8)) |
| 1292 | { |
| 1293 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" |
| 1294 | << " ll command packets must have a plen of 8" << std::endl; |
| 1295 | exit(0); |
| 1296 | } |
| 1297 | |
| 1298 | if (p_vci_tgt.cmdval and m_cmd_read_addr_fifo.wok()) |
| 1299 | { |
| 1300 | |
| 1301 | #if DEBUG_MEMC_TGT_CMD |
| 1302 | if (m_debug) |
| 1303 | std::cout << " <MEMC " << name() << " TGT_CMD_READ> Push into read_fifo:" |
| 1304 | << " address = " << std::hex << p_vci_tgt.address.read() |
| 1305 | << " / srcid = " << p_vci_tgt.srcid.read() |
| 1306 | << " / trdid = " << p_vci_tgt.trdid.read() |
| 1307 | << " / pktid = " << p_vci_tgt.pktid.read() |
| 1308 | << " / plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
| 1309 | #endif |
| 1310 | cmd_read_fifo_put = true; |
| 1311 | // <Activity counters> |
| 1312 | if (p_vci_tgt.cmd.read() == vci_param_int::CMD_LOCKED_READ) { |
| 1313 | if (is_local_req(p_vci_tgt.srcid.read())) m_cpt_ll_local++; |
| 1314 | else m_cpt_ll_remote++; |
| 1315 | m_cpt_ll_cost += req_distance(p_vci_tgt.srcid.read()); // LL on a single word |
| 1316 | } |
| 1317 | else { |
| 1318 | if (is_local_req(p_vci_tgt.srcid.read())) m_cpt_read_local++; |
| 1319 | else m_cpt_read_remote++; |
| 1320 | m_cpt_read_cost += m_words * req_distance(p_vci_tgt.srcid.read()); |
| 1321 | } |
| 1322 | // </Activity counters> |
| 1323 | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
| 1324 | } |
| 1325 | break; |
| 1326 | |
| 1327 | /////////////////// |
| 1328 | case TGT_CMD_WRITE: |
| 1329 | if (p_vci_tgt.cmdval and m_cmd_write_addr_fifo.wok()) |
| 1330 | { |
| 1331 | |
| 1332 | #if DEBUG_MEMC_TGT_CMD |
| 1333 | if (m_debug) |
| 1334 | std::cout << " <MEMC " << name() << " TGT_CMD_WRITE> Push into write_fifo:" |
| 1335 | << " address = " << std::hex << p_vci_tgt.address.read() |
| 1336 | << " / srcid = " << p_vci_tgt.srcid.read() |
| 1337 | << " / trdid = " << p_vci_tgt.trdid.read() |
| 1338 | << " / pktid = " << p_vci_tgt.pktid.read() |
| 1339 | << " / wdata = " << p_vci_tgt.wdata.read() |
| 1340 | << " / be = " << p_vci_tgt.be.read() |
| 1341 | << " / plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
| 1342 | #endif |
| 1343 | cmd_write_fifo_put = true; |
| 1344 | // <Activity counters> |
| 1345 | if (p_vci_tgt.cmd.read() == vci_param_int::CMD_NOP) { |
| 1346 | m_cpt_sc_cost += req_distance(p_vci_tgt.srcid.read()); |
| 1347 | } |
| 1348 | else { |
| 1349 | if (is_local_req(p_vci_tgt.srcid.read())) m_cpt_write_flits_local++; |
| 1350 | else m_cpt_write_flits_remote++; |
| 1351 | m_cpt_write_cost += req_distance(p_vci_tgt.srcid.read()); |
| 1352 | } |
| 1353 | // </Activity counters> |
| 1354 | |
| 1355 | if (p_vci_tgt.eop) { |
| 1356 | // <Activity counters> |
| 1357 | if (p_vci_tgt.cmd.read() == vci_param_int::CMD_NOP) { |
| 1358 | if (is_local_req(p_vci_tgt.srcid.read())) m_cpt_sc_local++; |
| 1359 | else m_cpt_sc_remote++; |
| 1360 | |
| 1361 | } |
| 1362 | else { |
| 1363 | if (is_local_req(p_vci_tgt.srcid.read())) m_cpt_write_local++; |
| 1364 | else m_cpt_write_remote++; |
| 1365 | } |
| 1366 | // </Activity counters> |
| 1367 | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
| 1368 | } |
| 1369 | } |
| 1370 | break; |
| 1371 | |
| 1372 | ///////////////// |
| 1373 | case TGT_CMD_CAS: |
| 1374 | if ((p_vci_tgt.plen.read() != 8) and (p_vci_tgt.plen.read() != 16)) |
| 1375 | { |
| 1376 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_CAS state" |
| 1377 | << "illegal format for CAS command " << std::endl; |
| 1378 | exit(0); |
| 1379 | } |
| 1380 | |
| 1381 | if (p_vci_tgt.cmdval and m_cmd_cas_addr_fifo.wok()) |
| 1382 | { |
| 1383 | |
| 1384 | #if DEBUG_MEMC_TGT_CMD |
| 1385 | if (m_debug) |
| 1386 | std::cout << " <MEMC " << name() << " TGT_CMD_CAS> Pushing command into cmd_cas_fifo:" |
| 1387 | << " address = " << std::hex << p_vci_tgt.address.read() |
| 1388 | << " srcid = " << p_vci_tgt.srcid.read() |
| 1389 | << " trdid = " << p_vci_tgt.trdid.read() |
| 1390 | << " pktid = " << p_vci_tgt.pktid.read() |
| 1391 | << " wdata = " << p_vci_tgt.wdata.read() |
| 1392 | << " be = " << p_vci_tgt.be.read() |
| 1393 | << " plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
| 1394 | #endif |
| 1395 | cmd_cas_fifo_put = true; |
| 1396 | if (p_vci_tgt.eop) { |
| 1397 | // <Activity counters> |
| 1398 | if (is_local_req(p_vci_tgt.srcid.read())) m_cpt_cas_local++; |
| 1399 | else m_cpt_cas_remote++; |
| 1400 | m_cpt_cas_cost += req_distance(p_vci_tgt.srcid.read()); |
| 1401 | // </Activity counters> |
| 1402 | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
| 1403 | } |
| 1404 | } |
| 1405 | break; |
| 1406 | } // end switch tgt_cmd_fsm |
| 1407 | |
| 1408 | ///////////////////////////////////////////////////////////////////////// |
| 1409 | // MULTI_ACK FSM |
| 1410 | ///////////////////////////////////////////////////////////////////////// |
| 1411 | // This FSM controls the response to the multicast update requests sent |
| 1412 | // by the memory cache to the L1 caches and update the UPT. |
| 1413 | // |
| 1414 | // - The FSM decrements the proper entry in UPT, |
| 1415 | // and clear the UPT entry when all responses have been received. |
| 1416 | // - If required, it sends a request to the TGT_RSP FSM to complete |
| 1417 | // a pending write transaction. |
| 1418 | // |
| 1419 | // All those multi-ack packets are one flit packet. |
| 1420 | // The index in the UPT is defined in the TRDID field. |
| 1421 | //////////////////////////////////////////////////////////////////////// |
| 1422 | |
| 1423 | //std::cout << std::endl << "multi_ack_fsm" << std::endl; |
| 1424 | |
| 1425 | switch(r_multi_ack_fsm.read()) |
1061 | | need_rsp = true; |
1062 | | error = 0; |
1063 | | r_config_lock = false; |
1064 | | } |
1065 | | else if ( (p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set addr_lo |
1066 | | and (cell == MEMC_ADDR_LO) ) |
| 1627 | ///////////////// |
| 1628 | case CONFIG_IDLE: // waiting a config request |
| 1629 | { |
| 1630 | if (r_config_cmd.read() != MEMC_CMD_NOP ) |
| 1631 | { |
| 1632 | r_config_fsm = CONFIG_LOOP; |
| 1633 | |
| 1634 | #if DEBUG_MEMC_CONFIG |
| 1635 | if (m_debug) |
| 1636 | std::cout << " <MEMC " << name() << " CONFIG_IDLE> Config Request received" |
| 1637 | << " / address = " << std::hex << r_config_address.read() |
| 1638 | << " / lines = " << std::dec << r_config_cmd_lines.read() |
| 1639 | << " / type = " << r_config_cmd.read() << std::endl; |
| 1640 | #endif |
| 1641 | } |
| 1642 | break; |
| 1643 | } |
| 1644 | ///////////////// |
| 1645 | case CONFIG_LOOP: // test if last line to be handled |
| 1646 | { |
| 1647 | if (r_config_cmd_lines.read() == 0 ) |
| 1648 | { |
| 1649 | r_config_cmd = MEMC_CMD_NOP; |
| 1650 | r_config_fsm = CONFIG_WAIT; |
| 1651 | } |
| 1652 | else |
| 1653 | { |
| 1654 | r_config_fsm = CONFIG_DIR_REQ; |
| 1655 | } |
| 1656 | |
| 1657 | #if DEBUG_MEMC_CONFIG |
| 1658 | if (m_debug) |
| 1659 | std::cout << " <MEMC " << name() << " CONFIG_LOOP>" |
| 1660 | << " / address = " << std::hex << r_config_address.read() |
| 1661 | << " / lines not handled = " << std::dec << r_config_cmd_lines.read() |
| 1662 | << " / command = " << r_config_cmd.read() << std::endl; |
| 1663 | #endif |
| 1664 | break; |
| 1665 | } |
| 1666 | ///////////////// |
| 1667 | case CONFIG_WAIT: // wait completion (last response) |
| 1668 | { |
| 1669 | if (r_config_rsp_lines.read() == 0 ) // last response received |
| 1670 | { |
| 1671 | r_config_fsm = CONFIG_RSP; |
| 1672 | } |
| 1673 | |
| 1674 | #if DEBUG_MEMC_CONFIG |
| 1675 | if (m_debug) |
| 1676 | std::cout << " <MEMC " << name() << " CONFIG_WAIT>" |
| 1677 | << " / lines to do = " << std::dec << r_config_rsp_lines.read() << std::endl; |
| 1678 | #endif |
| 1679 | break; |
| 1680 | } |
| 1681 | //////////////// |
| 1682 | case CONFIG_RSP: // request TGT_RSP FSM to return response |
| 1683 | { |
| 1684 | if (not r_config_to_tgt_rsp_req.read()) |
| 1685 | { |
| 1686 | r_config_to_tgt_rsp_srcid = r_config_srcid.read(); |
| 1687 | r_config_to_tgt_rsp_trdid = r_config_trdid.read(); |
| 1688 | r_config_to_tgt_rsp_pktid = r_config_pktid.read(); |
| 1689 | r_config_to_tgt_rsp_error = false; |
| 1690 | r_config_to_tgt_rsp_req = true; |
| 1691 | r_config_fsm = CONFIG_IDLE; |
| 1692 | |
| 1693 | #if DEBUG_MEMC_CONFIG |
| 1694 | if (m_debug) |
| 1695 | std::cout << " <MEMC " << name() << " CONFIG_RSP> Request TGT_RSP FSM to return response:" |
| 1696 | << " error = " << r_config_to_tgt_rsp_error.read() |
| 1697 | << " / rsrcid = " << std::hex << r_config_srcid.read() |
| 1698 | << " / rtrdid = " << std::hex << r_config_trdid.read() |
| 1699 | << " / rpktid = " << std::hex << r_config_pktid.read() << std::endl; |
| 1700 | #endif |
| 1701 | } |
| 1702 | break; |
| 1703 | |
| 1704 | } |
| 1705 | //////////////////// |
| 1706 | case CONFIG_DIR_REQ: // Request directory lock |
| 1707 | { |
| 1708 | if (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG ) |
| 1709 | { |
| 1710 | r_config_fsm = CONFIG_DIR_ACCESS; |
| 1711 | } |
| 1712 | |
| 1713 | #if DEBUG_MEMC_CONFIG |
| 1714 | if (m_debug) |
| 1715 | std::cout << " <MEMC " << name() << " CONFIG_DIR_REQ>" |
| 1716 | << " Request DIR access" << std::endl; |
| 1717 | #endif |
| 1718 | break; |
| 1719 | } |
| 1720 | /////////////////////// |
| 1721 | case CONFIG_DIR_ACCESS: // Access directory and decode config command |
| 1722 | { |
| 1723 | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
| 1724 | "MEMC ERROR in CONFIG_DIR_ACCESS state: bad DIR allocation"); |
| 1725 | |
| 1726 | size_t way = 0; |
| 1727 | DirectoryEntry entry = m_cache_directory.read(r_config_address.read(), way); |
| 1728 | |
| 1729 | r_config_dir_way = way; |
| 1730 | r_config_dir_copy_inst = entry.owner.inst; |
| 1731 | r_config_dir_copy_srcid = entry.owner.srcid; |
| 1732 | r_config_dir_is_cnt = entry.is_cnt; |
| 1733 | r_config_dir_lock = entry.lock; |
| 1734 | r_config_dir_count = entry.count; |
| 1735 | r_config_dir_ptr = entry.ptr; |
| 1736 | |
| 1737 | if (entry.valid and // hit & inval command |
| 1738 | (r_config_cmd.read() == MEMC_CMD_INVAL)) |
| 1739 | { |
| 1740 | r_config_fsm = CONFIG_IVT_LOCK; |
| 1741 | } |
| 1742 | else if (entry.valid and // hit & sync command |
| 1743 | entry.dirty and |
| 1744 | (r_config_cmd.read() == MEMC_CMD_SYNC)) |
| 1745 | { |
| 1746 | r_config_fsm = CONFIG_TRT_LOCK; |
| 1747 | } |
| 1748 | else // miss : return to LOOP |
| 1749 | { |
| 1750 | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
| 1751 | r_config_rsp_lines = r_config_rsp_lines.read() - 1; |
| 1752 | r_config_address = r_config_address.read() + (m_words<<2); |
| 1753 | r_config_fsm = CONFIG_LOOP; |
| 1754 | } |
| 1755 | |
| 1756 | #if DEBUG_MEMC_CONFIG |
| 1757 | if (m_debug) |
| 1758 | std::cout << " <MEMC " << name() << " CONFIG_DIR_ACCESS> Accessing directory: " |
| 1759 | << " address = " << std::hex << r_config_address.read() |
| 1760 | << " / hit = " << std::dec << entry.valid |
| 1761 | << " / dirty = " << entry.dirty |
| 1762 | << " / count = " << entry.count |
| 1763 | << " / is_cnt = " << entry.is_cnt << std::endl; |
| 1764 | #endif |
| 1765 | break; |
| 1766 | } |
| 1767 | ///////////////////// |
| 1768 | case CONFIG_TRT_LOCK: // enter this state in case of SYNC command |
| 1769 | // to a dirty cache line |
| 1770 | // keep DIR lock, and try to get TRT lock |
| 1771 | // return to LOOP state if TRT full |
| 1772 | // reset dirty bit in DIR and register a PUT |
| 1773 | // trabsaction in TRT if not full. |
| 1774 | { |
| 1775 | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
| 1776 | "MEMC ERROR in CONFIG_TRT_LOCK state: bad DIR allocation"); |
| 1777 | |
| 1778 | if (r_alloc_trt_fsm.read() == ALLOC_TRT_CONFIG ) |
| 1779 | { |
| 1780 | size_t index = 0; |
| 1781 | bool wok = not m_trt.full(index); |
| 1782 | |
| 1783 | if (not wok ) |
| 1784 | { |
| 1785 | r_config_fsm = CONFIG_LOOP; |
| 1786 | } |
| 1787 | else |
| 1788 | { |
| 1789 | size_t way = r_config_dir_way.read(); |
| 1790 | size_t set = m_y[r_config_address.read()]; |
| 1791 | |
| 1792 | // reset dirty bit in DIR |
| 1793 | DirectoryEntry entry; |
| 1794 | entry.valid = true; |
| 1795 | entry.dirty = false; |
| 1796 | entry.tag = m_z[r_config_address.read()]; |
| 1797 | entry.is_cnt = r_config_dir_is_cnt.read(); |
| 1798 | entry.lock = r_config_dir_lock.read(); |
| 1799 | entry.ptr = r_config_dir_ptr.read(); |
| 1800 | entry.count = r_config_dir_count.read(); |
| 1801 | entry.owner.inst = r_config_dir_copy_inst.read(); |
| 1802 | entry.owner.srcid = r_config_dir_copy_srcid.read(); |
| 1803 | m_cache_directory.write( set, way, entry ); |
| 1804 | |
| 1805 | r_config_trt_index = index; |
| 1806 | r_config_fsm = CONFIG_TRT_SET; |
| 1807 | } |
| 1808 | |
| 1809 | #if DEBUG_MEMC_CONFIG |
| 1810 | if (m_debug) |
| 1811 | std::cout << " <MEMC " << name() << " CONFIG_TRT_LOCK> Access TRT: " |
| 1812 | << " wok = " << std::dec << wok |
| 1813 | << " index = " << index << std::endl; |
| 1814 | #endif |
| 1815 | } |
| 1816 | break; |
| 1817 | } |
| 1818 | //////////////////// |
| 1819 | case CONFIG_TRT_SET: // read data in cache |
| 1820 | // and post a PUT request in TRT |
| 1821 | { |
| 1822 | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
| 1823 | "MEMC ERROR in CONFIG_TRT_SET state: bad DIR allocation"); |
| 1824 | |
| 1825 | assert( (r_alloc_trt_fsm.read() == ALLOC_TRT_CONFIG) and |
| 1826 | "MEMC ERROR in CONFIG_TRT_SET state: bad TRT allocation"); |
| 1827 | |
| 1828 | // read data into cache |
| 1829 | size_t way = r_config_dir_way.read(); |
| 1830 | size_t set = m_y[r_config_address.read()]; |
| 1831 | std::vector<data_t> data_vector; |
| 1832 | data_vector.clear(); |
| 1833 | for(size_t word=0; word<m_words; word++) |
| 1834 | { |
| 1835 | uint32_t data = m_cache_data.read( way, set, word ); |
| 1836 | data_vector.push_back( data ); |
| 1837 | } |
| 1838 | |
| 1839 | // post the PUT request in TRT |
| 1840 | m_trt.set( r_config_trt_index.read(), |
| 1841 | false, // PUT transaction |
| 1842 | m_nline[r_config_address.read()], // line index |
| 1843 | 0, // srcid: unused |
| 1844 | 0, // trdid: unused |
| 1845 | 0, // pktid: unused |
| 1846 | false, // not proc_read |
| 1847 | 0, // read_length: unused |
| 1848 | 0, // word_index: unused |
| 1849 | std::vector<be_t>(m_words,0xF), // byte-enable: unused |
| 1850 | data_vector, // data to be written |
| 1851 | 0, // ll_key: unused |
| 1852 | true ); // requested by config FSM |
| 1853 | r_config_fsm = CONFIG_PUT_REQ; |
| 1854 | |
| 1855 | #if DEBUG_MEMC_CONFIG |
| 1856 | if (m_debug) |
| 1857 | std::cout << " <MEMC " << name() << " CONFIG_TRT_SET> PUT request in TRT:" |
| 1858 | << " address = " << std::hex << r_config_address.read() |
| 1859 | << " index = " << std::dec << r_config_trt_index.read() << std::endl; |
| 1860 | #endif |
| 1861 | break; |
| 1862 | } |
| 1863 | //////////////////// |
| 1864 | case CONFIG_PUT_REQ: // post PUT request to IXR_CMD_FSM |
| 1865 | { |
| 1866 | if (not r_config_to_ixr_cmd_req.read()) |
| 1867 | { |
| 1868 | r_config_to_ixr_cmd_req = true; |
| 1869 | r_config_to_ixr_cmd_index = r_config_trt_index.read(); |
| 1870 | |
| 1871 | // prepare next iteration |
| 1872 | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
| 1873 | r_config_address = r_config_address.read() + (m_words<<2); |
| 1874 | r_config_fsm = CONFIG_LOOP; |
| 1875 | |
| 1876 | #if DEBUG_MEMC_CONFIG |
| 1877 | if (m_debug) |
| 1878 | std::cout << " <MEMC " << name() << " CONFIG_PUT_REQ> post PUT request to IXR_CMD_FSM" |
| 1879 | << " / address = " << std::hex << r_config_address.read() << std::endl; |
| 1880 | #endif |
| 1881 | } |
| 1882 | break; |
| 1883 | } |
| 1884 | ///////////////////// |
| 1885 | case CONFIG_IVT_LOCK: // enter this state in case of INVAL command |
| 1886 | // Keep DIR lock and Try to get IVT lock. |
| 1887 | // Return to LOOP state if IVT full. |
| 1888 | // Register inval in IVT, and invalidate the |
| 1889 | // directory if IVT not full. |
| 1890 | { |
| 1891 | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
| 1892 | "MEMC ERROR in CONFIG_IVT_LOCK state: bad DIR allocation"); |
| 1893 | |
| 1894 | if (r_alloc_ivt_fsm.read() == ALLOC_IVT_CONFIG ) |
| 1895 | { |
| 1896 | size_t set = m_y[(addr_t)(r_config_address.read())]; |
| 1897 | size_t way = r_config_dir_way.read(); |
| 1898 | |
| 1899 | if (r_config_dir_count.read() == 0 ) // inval DIR and return to LOOP |
| 1900 | { |
| 1901 | m_cache_directory.inval( way, set ); |
| 1902 | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
| 1903 | r_config_rsp_lines = r_config_rsp_lines.read() - 1; |
| 1904 | r_config_address = r_config_address.read() + (m_words<<2); |
| 1905 | r_config_fsm = CONFIG_LOOP; |
| 1906 | |
| 1907 | #if DEBUG_MEMC_CONFIG |
| 1908 | if (m_debug) |
| 1909 | std::cout << " <MEMC " << name() << " CONFIG_IVT_LOCK>" |
| 1910 | << " No copies in L1 : inval DIR entry" << std::endl; |
| 1911 | #endif |
| 1912 | } |
| 1913 | else // try to register inval in IVT |
| 1914 | { |
| 1915 | bool wok = false; |
| 1916 | size_t index = 0; |
| 1917 | bool broadcast = r_config_dir_is_cnt.read(); |
| 1918 | size_t srcid = r_config_srcid.read(); |
| 1919 | size_t trdid = r_config_trdid.read(); |
| 1920 | size_t pktid = r_config_pktid.read(); |
| 1921 | addr_t nline = m_nline[(addr_t)(r_config_address.read())]; |
| 1922 | size_t nb_copies = r_config_dir_count.read(); |
| 1923 | |
| 1924 | wok = m_ivt.set(false, // it's an inval transaction |
| 1925 | broadcast, |
| 1926 | false, // no response required |
| 1927 | true, // acknowledge required |
| 1928 | srcid, |
| 1929 | trdid, |
| 1930 | pktid, |
| 1931 | nline, |
| 1932 | nb_copies, |
| 1933 | index); |
| 1934 | |
| 1935 | if (wok ) // IVT success => inval DIR slot |
| 1936 | { |
| 1937 | m_cache_directory.inval( way, set ); |
| 1938 | r_config_ivt_index = index; |
| 1939 | if (broadcast ) r_config_fsm = CONFIG_BC_SEND; |
| 1940 | else r_config_fsm = CONFIG_INVAL_SEND; |
| 1941 | |
| 1942 | #if DEBUG_MEMC_CONFIG |
| 1943 | if (m_debug) |
| 1944 | std::cout << " <MEMC " << name() << " CONFIG_IVT_LOCK>" |
| 1945 | << " Inval DIR entry and register inval in IVT" |
| 1946 | << " / index = " << std::dec << index |
| 1947 | << " / broadcast = " << broadcast << std::endl; |
| 1948 | #endif |
| 1949 | } |
| 1950 | else // IVT full => release both DIR and IVT locks |
| 1951 | { |
| 1952 | r_config_fsm = CONFIG_LOOP; |
| 1953 | |
| 1954 | #if DEBUG_MEMC_CONFIG |
| 1955 | if (m_debug) |
| 1956 | std::cout << " <MEMC " << name() << " CONFIG_IVT_LOCK>" |
| 1957 | << " IVT full : release DIR & IVT locks and retry" << std::endl; |
| 1958 | #endif |
| 1959 | } |
| 1960 | } |
| 1961 | } |
| 1962 | break; |
| 1963 | } |
| 1964 | //////////////////// |
| 1965 | case CONFIG_BC_SEND: // Post a broadcast inval request to CC_SEND FSM |
| 1966 | { |
| 1967 | if (not r_config_to_cc_send_multi_req.read() and |
| 1968 | not r_config_to_cc_send_brdcast_req.read()) |
| 1969 | { |
| 1970 | // post bc inval request |
| 1971 | r_config_to_cc_send_multi_req = false; |
| 1972 | r_config_to_cc_send_brdcast_req = true; |
| 1973 | r_config_to_cc_send_trdid = r_config_ivt_index.read(); |
| 1974 | r_config_to_cc_send_nline = m_nline[(addr_t)(r_config_address.read())]; |
| 1975 | |
| 1976 | // prepare next iteration |
| 1977 | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
| 1978 | r_config_address = r_config_address.read() + (m_words << 2); |
| 1979 | r_config_fsm = CONFIG_LOOP; |
| 1980 | |
| 1981 | #if DEBUG_MEMC_CONFIG |
| 1982 | if (m_debug) |
| 1983 | std::cout << " <MEMC " << name() << " CONFIG_BC_SEND>" |
| 1984 | << " Post a broadcast inval request to CC_SEND FSM" |
| 1985 | << " / address = " << r_config_address.read() <<std::endl; |
| 1986 | #endif |
| 1987 | } |
| 1988 | break; |
| 1989 | } |
| 1990 | /////////////////////// |
| 1991 | case CONFIG_INVAL_SEND: // Post a multi inval request to CC_SEND FSM |
| 1992 | { |
| 1993 | if (not r_config_to_cc_send_multi_req.read() and |
| 1994 | not r_config_to_cc_send_brdcast_req.read()) |
| 1995 | { |
| 1996 | // post multi inval request |
| 1997 | r_config_to_cc_send_multi_req = true; |
| 1998 | r_config_to_cc_send_brdcast_req = false; |
| 1999 | r_config_to_cc_send_trdid = r_config_ivt_index.read(); |
| 2000 | r_config_to_cc_send_nline = m_nline[(addr_t) (r_config_address.read())]; |
| 2001 | |
| 2002 | // post data into FIFO |
| 2003 | config_to_cc_send_fifo_srcid = r_config_dir_copy_srcid.read(); |
| 2004 | config_to_cc_send_fifo_inst = r_config_dir_copy_inst.read(); |
| 2005 | config_to_cc_send_fifo_put = true; |
| 2006 | |
| 2007 | if (r_config_dir_count.read() == 1 ) // one copy |
| 2008 | { |
| 2009 | // prepare next iteration |
| 2010 | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
| 2011 | r_config_address = r_config_address.read() + (m_words << 2); |
| 2012 | r_config_fsm = CONFIG_LOOP; |
| 2013 | } |
| 2014 | else // several copies |
| 2015 | { |
| 2016 | r_config_fsm = CONFIG_HEAP_REQ; |
| 2017 | } |
| 2018 | |
| 2019 | #if DEBUG_MEMC_CONFIG |
| 2020 | if (m_debug) |
| 2021 | std::cout << " <MEMC " << name() << " CONFIG_INVAL_SEND>" |
| 2022 | << " Post multi inval request to CC_SEND FSM" |
| 2023 | << " / address = " << std::hex << r_config_address.read() |
| 2024 | << " / copy = " << r_config_dir_copy_srcid.read() |
| 2025 | << " / inst = " << std::dec << r_config_dir_copy_inst.read() << std::endl; |
| 2026 | #endif |
| 2027 | } |
| 2028 | break; |
| 2029 | } |
| 2030 | ///////////////////// |
| 2031 | case CONFIG_HEAP_REQ: // Try to get access to Heap |
| 2032 | { |
| 2033 | if (r_alloc_heap_fsm.read() == ALLOC_HEAP_CONFIG ) |
| 2034 | { |
| 2035 | r_config_fsm = CONFIG_HEAP_SCAN; |
| 2036 | r_config_heap_next = r_config_dir_ptr.read(); |
| 2037 | } |
| 2038 | |
| 2039 | #if DEBUG_MEMC_CONFIG |
| 2040 | if (m_debug) |
| 2041 | std::cout << " <MEMC " << name() << " CONFIG_HEAP_REQ>" |
| 2042 | << " Requesting HEAP lock" << std::endl; |
| 2043 | #endif |
| 2044 | break; |
| 2045 | } |
| 2046 | ////////////////////// |
| 2047 | case CONFIG_HEAP_SCAN: // scan HEAP and send inval to CC_SEND FSM |
| 2048 | { |
| 2049 | HeapEntry entry = m_heap.read( r_config_heap_next.read()); |
| 2050 | bool last_copy = (entry.next == r_config_heap_next.read()); |
| 2051 | |
| 2052 | config_to_cc_send_fifo_srcid = entry.owner.srcid; |
| 2053 | config_to_cc_send_fifo_inst = entry.owner.inst; |
| 2054 | // config_to_cc_send_fifo_last = last_copy; |
| 2055 | config_to_cc_send_fifo_put = true; |
| 2056 | |
| 2057 | if (m_config_to_cc_send_inst_fifo.wok()) // inval request accepted |
| 2058 | { |
| 2059 | r_config_heap_next = entry.next; |
| 2060 | if (last_copy ) r_config_fsm = CONFIG_HEAP_LAST; |
| 2061 | } |
| 2062 | |
| 2063 | #if DEBUG_MEMC_CONFIG |
| 2064 | if (m_debug) |
| 2065 | std::cout << " <MEMC " << name() << " CONFIG_HEAP_SCAN>" |
| 2066 | << " Post multi inval request to CC_SEND FSM" |
| 2067 | << " / address = " << std::hex << r_config_address.read() |
| 2068 | << " / copy = " << entry.owner.srcid |
| 2069 | << " / inst = " << std::dec << entry.owner.inst << std::endl; |
| 2070 | #endif |
| 2071 | break; |
| 2072 | } |
| 2073 | ////////////////////// |
| 2074 | case CONFIG_HEAP_LAST: // HEAP housekeeping |
| 2075 | { |
| 2076 | size_t free_pointer = m_heap.next_free_ptr(); |
| 2077 | HeapEntry last_entry; |
| 2078 | last_entry.owner.srcid = 0; |
| 2079 | last_entry.owner.inst = false; |
| 2080 | |
| 2081 | if (m_heap.is_full()) |
| 2082 | { |
| 2083 | last_entry.next = r_config_dir_ptr.read(); |
| 2084 | m_heap.unset_full(); |
| 2085 | } |
| 2086 | else |
| 2087 | { |
| 2088 | last_entry.next = free_pointer; |
| 2089 | } |
| 2090 | |
| 2091 | m_heap.write_free_ptr( r_config_dir_ptr.read()); |
| 2092 | m_heap.write( r_config_heap_next.read(), last_entry ); |
| 2093 | |
| 2094 | // prepare next iteration |
| 2095 | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
| 2096 | r_config_address = r_config_address.read() + (m_words<<2); |
| 2097 | r_config_fsm = CONFIG_LOOP; |
| 2098 | |
| 2099 | #if DEBUG_MEMC_CONFIG |
| 2100 | if (m_debug) |
| 2101 | std::cout << " <MEMC " << name() << " CONFIG_HEAP_LAST>" |
| 2102 | << " Heap housekeeping" << std::endl; |
| 2103 | #endif |
| 2104 | break; |
| 2105 | } |
| 2106 | } // end switch r_config_fsm |
| 2107 | |
| 2108 | //////////////////////////////////////////////////////////////////////////////////// |
| 2109 | // READ FSM |
| 2110 | //////////////////////////////////////////////////////////////////////////////////// |
| 2111 | // The READ FSM controls the VCI read and ll requests. |
| 2112 | // It takes the lock protecting the cache directory to check the cache line status: |
| 2113 | // - In case of HIT |
| 2114 | // The fsm copies the data (one line, or one single word) |
| 2115 | // in the r_read_to_tgt_rsp buffer. It waits if this buffer is not empty. |
| 2116 | // The requesting initiator is registered in the cache directory. |
| 2117 | // If the number of copy is larger than 1, the new copy is registered |
| 2118 | // in the HEAP. |
| 2119 | // If the number of copy is larger than the threshold, the HEAP is cleared, |
| 2120 | // and the corresponding line switches to the counter mode. |
| 2121 | // - In case of MISS |
| 2122 | // The READ fsm takes the lock protecting the transaction tab. |
| 2123 | // If a read transaction to the XRAM for this line already exists, |
| 2124 | // or if the transaction tab is full, the fsm is stalled. |
| 2125 | // If a TRT entry is free, the READ request is registered in TRT, |
| 2126 | // it is consumed in the request FIFO, and transmited to the IXR_CMD FSM. |
| 2127 | // The READ FSM returns in the IDLE state as the read transaction will be |
| 2128 | // completed when the missing line will be received. |
| 2129 | //////////////////////////////////////////////////////////////////////////////////// |
| 2130 | |
| 2131 | //std::cout << std::endl << "read_fsm" << std::endl; |
| 2132 | |
| 2133 | switch(r_read_fsm.read()) |
1068 | | assert( ((wdata % (m_words*vci_param_int::B)) == 0) and |
1069 | | "VCI_MEM_CACHE CONFIG ERROR: The buffer must be aligned on a cache line"); |
1070 | | |
1071 | | need_rsp = true; |
1072 | | error = 0; |
1073 | | r_config_address = (r_config_address.read() & 0xFFFFFFFF00000000LL) | |
1074 | | ((addr_t)wdata); |
1075 | | } |
1076 | | else if ( (p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set addr_hi |
1077 | | and (cell == MEMC_ADDR_HI) ) |
1078 | | |
| 2135 | /////////////// |
| 2136 | case READ_IDLE: // waiting a read request |
| 2137 | { |
| 2138 | if (m_cmd_read_addr_fifo.rok()) |
| 2139 | { |
| 2140 | |
| 2141 | #if DEBUG_MEMC_READ |
| 2142 | if (m_debug) |
| 2143 | std::cout << " <MEMC " << name() << " READ_IDLE> Read request" |
| 2144 | << " : address = " << std::hex << m_cmd_read_addr_fifo.read() |
| 2145 | << " / srcid = " << m_cmd_read_srcid_fifo.read() |
| 2146 | << " / trdid = " << m_cmd_read_trdid_fifo.read() |
| 2147 | << " / pktid = " << m_cmd_read_pktid_fifo.read() |
| 2148 | << " / nwords = " << std::dec << m_cmd_read_length_fifo.read() << std::endl; |
| 2149 | #endif |
| 2150 | r_read_fsm = READ_DIR_REQ; |
| 2151 | } |
| 2152 | break; |
| 2153 | } |
| 2154 | ////////////////// |
| 2155 | case READ_DIR_REQ: // Get the lock to the directory |
| 2156 | { |
| 2157 | if (r_alloc_dir_fsm.read() == ALLOC_DIR_READ) |
| 2158 | { |
| 2159 | r_read_fsm = READ_DIR_LOCK; |
| 2160 | } |
| 2161 | |
| 2162 | #if DEBUG_MEMC_READ |
| 2163 | if (m_debug) |
| 2164 | std::cout << " <MEMC " << name() << " READ_DIR_REQ> Requesting DIR lock " << std::endl; |
| 2165 | #endif |
| 2166 | break; |
| 2167 | } |
| 2168 | |
| 2169 | /////////////////// |
| 2170 | case READ_DIR_LOCK: // check directory for hit / miss |
| 2171 | { |
| 2172 | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_READ) and |
| 2173 | "MEMC ERROR in READ_DIR_LOCK state: Bad DIR allocation"); |
| 2174 | |
| 2175 | size_t way = 0; |
| 2176 | DirectoryEntry entry = m_cache_directory.read(m_cmd_read_addr_fifo.read(), way); |
| 2177 | |
| 2178 | // access the global table ONLY when we have an LL cmd |
| 2179 | if ((m_cmd_read_pktid_fifo.read() & 0x7) == TYPE_LL) |
| 2180 | { |
| 2181 | r_read_ll_key = m_llsc_table.ll(m_cmd_read_addr_fifo.read()); |
| 2182 | } |
| 2183 | r_read_is_cnt = entry.is_cnt; |
| 2184 | r_read_dirty = entry.dirty; |
| 2185 | r_read_lock = entry.lock; |
| 2186 | r_read_tag = entry.tag; |
| 2187 | r_read_way = way; |
| 2188 | r_read_count = entry.count; |
| 2189 | r_read_copy = entry.owner.srcid; |
| 2190 | r_read_copy_inst = entry.owner.inst; |
| 2191 | r_read_ptr = entry.ptr; // pointer to the heap |
| 2192 | |
| 2193 | // check if this is a cached read, this means pktid is either |
| 2194 | // TYPE_READ_DATA_MISS 0bX001 with TSAR encoding |
| 2195 | // TYPE_READ_INS_MISS 0bX011 with TSAR encoding |
| 2196 | bool cached_read = (m_cmd_read_pktid_fifo.read() & 0x1); |
| 2197 | if (entry.valid) // hit |
| 2198 | { |
| 2199 | // test if we need to register a new copy in the heap |
| 2200 | if (entry.is_cnt or (entry.count == 0) or !cached_read) |
| 2201 | { |
| 2202 | r_read_fsm = READ_DIR_HIT; |
| 2203 | } |
| 2204 | else |
| 2205 | { |
| 2206 | r_read_fsm = READ_HEAP_REQ; |
| 2207 | } |
| 2208 | } |
| 2209 | else // miss |
| 2210 | { |
| 2211 | r_read_fsm = READ_TRT_LOCK; |
| 2212 | } |
| 2213 | |
| 2214 | #if DEBUG_MEMC_READ |
| 2215 | if (m_debug) |
| 2216 | { |
| 2217 | std::cout << " <MEMC " << name() << " READ_DIR_LOCK> Accessing directory: " |
| 2218 | << " address = " << std::hex << m_cmd_read_addr_fifo.read() |
| 2219 | << " / hit = " << std::dec << entry.valid |
| 2220 | << " / count = " <<std::dec << entry.count |
| 2221 | << " / is_cnt = " << entry.is_cnt; |
| 2222 | if ((m_cmd_read_pktid_fifo.read() & 0x7) == TYPE_LL) std::cout << " / LL access" << std::endl; |
| 2223 | else std::cout << std::endl; |
| 2224 | } |
| 2225 | #endif |
| 2226 | break; |
| 2227 | } |
| 2228 | ////////////////// |
| 2229 | case READ_DIR_HIT: // read data in cache & update the directory |
| 2230 | // we enter this state in 3 cases: |
| 2231 | // - the read request is uncachable |
| 2232 | // - the cache line is in counter mode |
| 2233 | // - the cache line is valid but not replicated |
| 2234 | |
| 2235 | { |
| 2236 | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_READ) and |
| 2237 | "MEMC ERROR in READ_DIR_HIT state: Bad DIR allocation"); |
| 2238 | |
| 2239 | // check if this is an instruction read, this means pktid is either |
| 2240 | // TYPE_READ_INS_UNC 0bX010 with TSAR encoding |
| 2241 | // TYPE_READ_INS_MISS 0bX011 with TSAR encoding |
| 2242 | bool inst_read = ((m_cmd_read_pktid_fifo.read() & 0x2) != 0); |
| 2243 | // check if this is a cached read, this means pktid is either |
| 2244 | // TYPE_READ_DATA_MISS 0bX001 with TSAR encoding |
| 2245 | // TYPE_READ_INS_MISS 0bX011 with TSAR encoding |
| 2246 | bool cached_read = (m_cmd_read_pktid_fifo.read() & 0x1); |
| 2247 | bool is_cnt = r_read_is_cnt.read(); |
| 2248 | |
| 2249 | // read data in the cache |
| 2250 | size_t set = m_y[(addr_t)(m_cmd_read_addr_fifo.read())]; |
| 2251 | size_t way = r_read_way.read(); |
| 2252 | |
| 2253 | m_cache_data.read_line(way, set, r_read_data); |
| 2254 | |
| 2255 | // update the cache directory |
| 2256 | DirectoryEntry entry; |
| 2257 | entry.valid = true; |
| 2258 | entry.is_cnt = is_cnt; |
| 2259 | entry.dirty = r_read_dirty.read(); |
| 2260 | entry.tag = r_read_tag.read(); |
| 2261 | entry.lock = r_read_lock.read(); |
| 2262 | entry.ptr = r_read_ptr.read(); |
| 2263 | |
| 2264 | if (cached_read) // Cached read => we must update the copies |
| 2265 | { |
| 2266 | if (!is_cnt) // Not counter mode |
| 2267 | { |
| 2268 | entry.owner.srcid = m_cmd_read_srcid_fifo.read(); |
| 2269 | entry.owner.inst = inst_read; |
| 2270 | entry.count = r_read_count.read() + 1; |
| 2271 | } |
| 2272 | else // Counter mode |
| 2273 | { |
| 2274 | entry.owner.srcid = 0; |
| 2275 | entry.owner.inst = false; |
| 2276 | entry.count = r_read_count.read() + 1; |
| 2277 | } |
| 2278 | } |
| 2279 | else // Uncached read |
| 2280 | { |
| 2281 | entry.owner.srcid = r_read_copy.read(); |
| 2282 | entry.owner.inst = r_read_copy_inst.read(); |
| 2283 | entry.count = r_read_count.read(); |
| 2284 | } |
| 2285 | |
| 2286 | #if DEBUG_MEMC_READ |
| 2287 | if (m_debug) |
| 2288 | std::cout << " <MEMC " << name() << " READ_DIR_HIT> Update directory entry:" |
| 2289 | << " addr = " << std::hex << m_cmd_read_addr_fifo.read() |
| 2290 | << " / set = " << std::dec << set |
| 2291 | << " / way = " << way |
| 2292 | << " / owner_id = " << std::hex << entry.owner.srcid |
| 2293 | << " / owner_ins = " << std::dec << entry.owner.inst |
| 2294 | << " / count = " << entry.count |
| 2295 | << " / is_cnt = " << entry.is_cnt << std::endl; |
| 2296 | #endif |
| 2297 | m_cache_directory.write(set, way, entry); |
| 2298 | r_read_fsm = READ_RSP; |
| 2299 | break; |
| 2300 | } |
| 2301 | /////////////////// |
| 2302 | case READ_HEAP_REQ: // Get the lock to the HEAP directory |
| 2303 | { |
| 2304 | if (r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
| 2305 | { |
| 2306 | r_read_fsm = READ_HEAP_LOCK; |
| 2307 | } |
| 2308 | |
| 2309 | #if DEBUG_MEMC_READ |
| 2310 | if (m_debug) |
| 2311 | std::cout << " <MEMC " << name() << " READ_HEAP_REQ>" |
| 2312 | << " Requesting HEAP lock " << std::endl; |
| 2313 | #endif |
| 2314 | break; |
| 2315 | } |
| 2316 | |
| 2317 | //////////////////// |
| 2318 | case READ_HEAP_LOCK: // read data in cache, update the directory |
| 2319 | // and prepare the HEAP update |
| 2320 | { |
| 2321 | if (r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
| 2322 | { |
| 2323 | // enter counter mode when we reach the limit of copies or the heap is full |
| 2324 | bool go_cnt = (r_read_count.read() >= m_max_copies) or m_heap.is_full(); |
| 2325 | |
| 2326 | // read data in the cache |
| 2327 | size_t set = m_y[(addr_t)(m_cmd_read_addr_fifo.read())]; |
| 2328 | size_t way = r_read_way.read(); |
| 2329 | |
| 2330 | m_cache_data.read_line(way, set, r_read_data); |
| 2331 | |
| 2332 | // update the cache directory |
| 2333 | DirectoryEntry entry; |
| 2334 | entry.valid = true; |
| 2335 | entry.is_cnt = go_cnt; |
| 2336 | entry.dirty = r_read_dirty.read(); |
| 2337 | entry.tag = r_read_tag.read(); |
| 2338 | entry.lock = r_read_lock.read(); |
| 2339 | entry.count = r_read_count.read() + 1; |
| 2340 | |
| 2341 | if (not go_cnt) // Not entering counter mode |
| 2342 | { |
| 2343 | entry.owner.srcid = r_read_copy.read(); |
| 2344 | entry.owner.inst = r_read_copy_inst.read(); |
| 2345 | entry.ptr = m_heap.next_free_ptr(); // set pointer on the heap |
| 2346 | } |
| 2347 | else // Entering Counter mode |
| 2348 | { |
| 2349 | entry.owner.srcid = 0; |
| 2350 | entry.owner.inst = false; |
| 2351 | entry.ptr = 0; |
| 2352 | } |
| 2353 | |
| 2354 | m_cache_directory.write(set, way, entry); |
| 2355 | |
| 2356 | // prepare the heap update (add an entry, or clear the linked list) |
| 2357 | if (not go_cnt) // not switching to counter mode |
| 2358 | { |
| 2359 | // We test if the next free entry in the heap is the last |
| 2360 | HeapEntry heap_entry = m_heap.next_free_entry(); |
| 2361 | r_read_next_ptr = heap_entry.next; |
| 2362 | r_read_last_free = (heap_entry.next == m_heap.next_free_ptr()); |
| 2363 | |
| 2364 | r_read_fsm = READ_HEAP_WRITE; // add an entry in the HEAP |
| 2365 | } |
| 2366 | else // switching to counter mode |
| 2367 | { |
| 2368 | if (r_read_count.read() >1) // heap must be cleared |
| 2369 | { |
| 2370 | HeapEntry next_entry = m_heap.read(r_read_ptr.read()); |
| 2371 | r_read_next_ptr = m_heap.next_free_ptr(); |
| 2372 | m_heap.write_free_ptr(r_read_ptr.read()); |
| 2373 | |
| 2374 | if (next_entry.next == r_read_ptr.read()) // last entry |
| 2375 | { |
| 2376 | r_read_fsm = READ_HEAP_LAST; // erase the entry |
| 2377 | } |
| 2378 | else // not the last entry |
| 2379 | { |
| 2380 | r_read_ptr = next_entry.next; |
| 2381 | r_read_fsm = READ_HEAP_ERASE; // erase the list |
| 2382 | } |
| 2383 | } |
| 2384 | else // the heap is not used / nothing to do |
| 2385 | { |
| 2386 | r_read_fsm = READ_RSP; |
| 2387 | } |
| 2388 | } |
| 2389 | |
| 2390 | #if DEBUG_MEMC_READ |
| 2391 | if (m_debug) |
| 2392 | std::cout << " <MEMC " << name() << " READ_HEAP_LOCK> Update directory:" |
| 2393 | << " tag = " << std::hex << entry.tag |
| 2394 | << " set = " << std::dec << set |
| 2395 | << " way = " << way |
| 2396 | << " count = " << entry.count |
| 2397 | << " is_cnt = " << entry.is_cnt << std::endl; |
| 2398 | #endif |
| 2399 | } |
| 2400 | else |
| 2401 | { |
| 2402 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_LOCK" |
| 2403 | << "Bad HEAP allocation" << std::endl; |
| 2404 | exit(0); |
| 2405 | } |
| 2406 | break; |
| 2407 | } |
| 2408 | ///////////////////// |
| 2409 | case READ_HEAP_WRITE: // add an entry in the heap |
| 2410 | { |
| 2411 | if (r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
| 2412 | { |
| 2413 | HeapEntry heap_entry; |
| 2414 | heap_entry.owner.srcid = m_cmd_read_srcid_fifo.read(); |
| 2415 | heap_entry.owner.inst = ((m_cmd_read_pktid_fifo.read() & 0x2) != 0); |
| 2416 | |
| 2417 | if (r_read_count.read() == 1) // creation of a new linked list |
| 2418 | { |
| 2419 | heap_entry.next = m_heap.next_free_ptr(); |
| 2420 | } |
| 2421 | else // head insertion in existing list |
| 2422 | { |
| 2423 | heap_entry.next = r_read_ptr.read(); |
| 2424 | } |
| 2425 | m_heap.write_free_entry(heap_entry); |
| 2426 | m_heap.write_free_ptr(r_read_next_ptr.read()); |
| 2427 | if (r_read_last_free.read()) m_heap.set_full(); |
| 2428 | |
| 2429 | r_read_fsm = READ_RSP; |
| 2430 | |
| 2431 | #if DEBUG_MEMC_READ |
| 2432 | if (m_debug) |
| 2433 | std::cout << " <MEMC " << name() << " READ_HEAP_WRITE> Add an entry in the heap:" |
| 2434 | << " owner_id = " << std::hex << heap_entry.owner.srcid |
| 2435 | << " owner_ins = " << std::dec << heap_entry.owner.inst << std::endl; |
| 2436 | #endif |
| 2437 | } |
| 2438 | else |
| 2439 | { |
| 2440 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_WRITE" |
| 2441 | << "Bad HEAP allocation" << std::endl; |
| 2442 | exit(0); |
| 2443 | } |
| 2444 | break; |
| 2445 | } |
| 2446 | ///////////////////// |
| 2447 | case READ_HEAP_ERASE: |
| 2448 | { |
| 2449 | if (r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
| 2450 | { |
| 2451 | HeapEntry next_entry = m_heap.read(r_read_ptr.read()); |
| 2452 | if (next_entry.next == r_read_ptr.read()) |
| 2453 | { |
| 2454 | r_read_fsm = READ_HEAP_LAST; |
| 2455 | } |
| 2456 | else |
| 2457 | { |
| 2458 | r_read_ptr = next_entry.next; |
| 2459 | r_read_fsm = READ_HEAP_ERASE; |
| 2460 | } |
| 2461 | } |
| 2462 | else |
| 2463 | { |
| 2464 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_ERASE" |
| 2465 | << "Bad HEAP allocation" << std::endl; |
| 2466 | exit(0); |
| 2467 | } |
| 2468 | break; |
| 2469 | } |
| 2470 | |
| 2471 | //////////////////// |
| 2472 | case READ_HEAP_LAST: |
| 2473 | { |
| 2474 | if (r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
| 2475 | { |
| 2476 | HeapEntry last_entry; |
| 2477 | last_entry.owner.srcid = 0; |
| 2478 | last_entry.owner.inst = false; |
| 2479 | |
| 2480 | if (m_heap.is_full()) |
| 2481 | { |
| 2482 | last_entry.next = r_read_ptr.read(); |
| 2483 | m_heap.unset_full(); |
| 2484 | } |
| 2485 | else |
| 2486 | { |
| 2487 | last_entry.next = r_read_next_ptr.read(); |
| 2488 | } |
| 2489 | m_heap.write(r_read_ptr.read(),last_entry); |
| 2490 | r_read_fsm = READ_RSP; |
| 2491 | } |
| 2492 | else |
| 2493 | { |
| 2494 | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_LAST" |
| 2495 | << "Bad HEAP allocation" << std::endl; |
| 2496 | exit(0); |
| 2497 | } |
| 2498 | break; |
| 2499 | } |
| 2500 | ////////////// |
| 2501 | case READ_RSP: // request the TGT_RSP FSM to return data |
| 2502 | { |
| 2503 | if (!r_read_to_tgt_rsp_req) |
| 2504 | { |
| 2505 | for(size_t i=0 ; i<m_words ; i++) r_read_to_tgt_rsp_data[i] = r_read_data[i]; |
| 2506 | r_read_to_tgt_rsp_word = m_x[(addr_t) m_cmd_read_addr_fifo.read()]; |
| 2507 | r_read_to_tgt_rsp_length = m_cmd_read_length_fifo.read(); |
| 2508 | r_read_to_tgt_rsp_srcid = m_cmd_read_srcid_fifo.read(); |
| 2509 | r_read_to_tgt_rsp_trdid = m_cmd_read_trdid_fifo.read(); |
| 2510 | r_read_to_tgt_rsp_pktid = m_cmd_read_pktid_fifo.read(); |
| 2511 | r_read_to_tgt_rsp_ll_key = r_read_ll_key.read(); |
| 2512 | cmd_read_fifo_get = true; |
| 2513 | r_read_to_tgt_rsp_req = true; |
| 2514 | r_read_fsm = READ_IDLE; |
| 2515 | |
| 2516 | #if DEBUG_MEMC_READ |
| 2517 | if (m_debug) |
| 2518 | std::cout << " <MEMC " << name() << " READ_RSP> Request TGT_RSP FSM to return data:" |
| 2519 | << " rsrcid = " << std::hex << m_cmd_read_srcid_fifo.read() |
| 2520 | << " / address = " << std::hex << m_cmd_read_addr_fifo.read() |
| 2521 | << " / nwords = " << std::dec << m_cmd_read_length_fifo.read() << std::endl; |
| 2522 | #endif |
| 2523 | } |
| 2524 | break; |
| 2525 | } |
| 2526 | /////////////////// |
| 2527 | case READ_TRT_LOCK: // read miss : check the Transaction Table |
| 2528 | { |
| 2529 | if (r_alloc_trt_fsm.read() == ALLOC_TRT_READ) |
| 2530 | { |
| 2531 | size_t index = 0; |
| 2532 | addr_t addr = (addr_t) m_cmd_read_addr_fifo.read(); |
| 2533 | bool hit_read = m_trt.hit_read(m_nline[addr], index); |
| 2534 | bool hit_write = m_trt.hit_write(m_nline[addr]); |
| 2535 | bool wok = not m_trt.full(index); |
| 2536 | |
| 2537 | if (hit_read or !wok or hit_write) // line already requested or no space |
| 2538 | { |
| 2539 | if (!wok) m_cpt_trt_full++; |
| 2540 | if (hit_read or hit_write) m_cpt_trt_rb++; |
| 2541 | r_read_fsm = READ_IDLE; |
| 2542 | } |
| 2543 | else // missing line is requested to the XRAM |
| 2544 | { |
| 2545 | m_cpt_read_miss++; |
| 2546 | r_read_trt_index = index; |
| 2547 | r_read_fsm = READ_TRT_SET; |
| 2548 | } |
| 2549 | |
| 2550 | #if DEBUG_MEMC_READ |
| 2551 | if (m_debug) |
| 2552 | std::cout << " <MEMC " << name() << " READ_TRT_LOCK> Check TRT:" |
| 2553 | << " hit_read = " << hit_read |
| 2554 | << " / hit_write = " << hit_write |
| 2555 | << " / full = " << !wok << std::endl; |
| 2556 | #endif |
| 2557 | } |
| 2558 | break; |
| 2559 | } |
| 2560 | ////////////////// |
| 2561 | case READ_TRT_SET: // register get transaction in TRT |
| 2562 | { |
| 2563 | if (r_alloc_trt_fsm.read() == ALLOC_TRT_READ) |
| 2564 | { |
| 2565 | m_trt.set( r_read_trt_index.read(), |
| 2566 | true, // GET |
| 2567 | m_nline[(addr_t)(m_cmd_read_addr_fifo.read())], |
| 2568 | m_cmd_read_srcid_fifo.read(), |
| 2569 | m_cmd_read_trdid_fifo.read(), |
| 2570 | m_cmd_read_pktid_fifo.read(), |
| 2571 | true, // proc read |
| 2572 | m_cmd_read_length_fifo.read(), |
| 2573 | m_x[(addr_t)(m_cmd_read_addr_fifo.read())], |
| 2574 | std::vector<be_t> (m_words,0), |
| 2575 | std::vector<data_t> (m_words,0), |
| 2576 | r_read_ll_key.read()); |
| 2577 | #if DEBUG_MEMC_READ |
| 2578 | if (m_debug) |
| 2579 | std::cout << " <MEMC " << name() << " READ_TRT_SET> Set a GET in TRT:" |
| 2580 | << " address = " << std::hex << m_cmd_read_addr_fifo.read() |
| 2581 | << " / srcid = " << std::hex << m_cmd_read_srcid_fifo.read() << std::endl; |
| 2582 | #endif |
| 2583 | r_read_fsm = READ_TRT_REQ; |
| 2584 | } |
| 2585 | break; |
| 2586 | } |
| 2587 | |
| 2588 | ////////////////// |
| 2589 | case READ_TRT_REQ: // consume the read request in FIFO and send it to IXR_CMD_FSM |
| 2590 | { |
| 2591 | if (not r_read_to_ixr_cmd_req) |
| 2592 | { |
| 2593 | cmd_read_fifo_get = true; |
| 2594 | r_read_to_ixr_cmd_req = true; |
| 2595 | r_read_to_ixr_cmd_index = r_read_trt_index.read(); |
| 2596 | r_read_fsm = READ_IDLE; |
| 2597 | |
| 2598 | #if DEBUG_MEMC_READ |
| 2599 | if (m_debug) |
| 2600 | std::cout << " <MEMC " << name() << " READ_TRT_REQ> Request GET transaction for address " |
| 2601 | << std::hex << m_cmd_read_addr_fifo.read() << std::endl; |
| 2602 | #endif |
| 2603 | } |
| 2604 | break; |
| 2605 | } |
| 2606 | } // end switch read_fsm |
| 2607 | |
| 2608 | /////////////////////////////////////////////////////////////////////////////////// |
| 2609 | // WRITE FSM |
| 2610 | /////////////////////////////////////////////////////////////////////////////////// |
| 2611 | // The WRITE FSM handles the write bursts and sc requests sent by the processors. |
| 2612 | // All addresses in a burst must be in the same cache line. |
| 2613 | // A complete write burst is consumed in the FIFO & copied to a local buffer. |
| 2614 | // Then the FSM takes the lock protecting the cache directory, to check |
| 2615 | // if the line is in the cache. |
| 2616 | // |
| 2617 | // - In case of HIT, the cache is updated. |
| 2618 | // If there is no other copy, an acknowledge response is immediately |
| 2619 | // returned to the writing processor. |
| 2620 | // If the data is cached by other processors, a coherence transaction must |
| 2621 | // be launched (sc requests always require a coherence transaction): |
| 2622 | // It is a multicast update if the line is not in counter mode: the processor |
| 2623 | // takes the lock protecting the Update Table (UPT) to register this transaction. |
| 2624 | // If the UPT is full, it releases the lock(s) and retry. Then, it sends |
| 2625 | // a multi-update request to all owners of the line (but the writer), |
| 2626 | // through the CC_SEND FSM. In case of coherence transaction, the WRITE FSM |
| 2627 | // does not respond to the writing processor, as this response will be sent by |
| 2628 | // the MULTI_ACK FSM when all update responses have been received. |
| 2629 | // It is a broadcast invalidate if the line is in counter mode: The line |
| 2630 | // should be erased in memory cache, and written in XRAM with a PUT transaction, |
| 2631 | // after registration in TRT. |
| 2632 | // |
| 2633 | // - In case of MISS, the WRITE FSM takes the lock protecting the transaction |
| 2634 | // table (TRT). If a read transaction to the XRAM for this line already exists, |
| 2635 | // it writes in the TRT (write buffer). Otherwise, if a TRT entry is free, |
| 2636 | // the WRITE FSM register a new transaction in TRT, and sends a GET request |
| 2637 | // to the XRAM. If the TRT is full, it releases the lock, and waits. |
| 2638 | // Finally, the WRITE FSM returns an aknowledge response to the writing processor. |
| 2639 | ///////////////////////////////////////////////////////////////////////////////////// |
| 2640 | |
| 2641 | //std::cout << std::endl << "write_fsm" << std::endl; |
| 2642 | |
| 2643 | switch(r_write_fsm.read()) |
1080 | | need_rsp = true; |
1081 | | error = 0; |
1082 | | r_config_address = (r_config_address.read() & 0x00000000FFFFFFFFLL) | |
1083 | | (((addr_t)wdata)<<32); |
1084 | | } |
1085 | | else if ( (p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set buf_lines |
1086 | | and (cell == MEMC_BUF_LENGTH) ) |
1087 | | { |
1088 | | need_rsp = true; |
1089 | | error = 0; |
1090 | | size_t lines = wdata/(m_words<<2); |
1091 | | if ( wdata%(m_words<<2) ) lines++; |
1092 | | r_config_cmd_lines = lines; |
1093 | | r_config_rsp_lines = lines; |
1094 | | } |
1095 | | else if ( (p_vci_tgt.cmd.read() == vci_param_int::CMD_WRITE) // set cmd type |
1096 | | and (cell == MEMC_CMD_TYPE) ) |
1097 | | { |
1098 | | need_rsp = false; |
1099 | | error = 0; |
1100 | | r_config_cmd = wdata; |
1101 | | |
1102 | | // prepare delayed response from CONFIG FSM |
1103 | | r_config_srcid = p_vci_tgt.srcid.read(); |
1104 | | r_config_trdid = p_vci_tgt.trdid.read(); |
1105 | | r_config_pktid = p_vci_tgt.pktid.read(); |
1106 | | } |
1107 | | else |
1108 | | { |
1109 | | need_rsp = true; |
1110 | | error = 1; |
1111 | | } |
1112 | | |
1113 | | if ( need_rsp ) |
1114 | | { |
1115 | | // blocked if previous pending request to TGT_RSP FSM |
1116 | | if ( r_tgt_cmd_to_tgt_rsp_req.read() ) break; |
1117 | | |
1118 | | r_tgt_cmd_to_tgt_rsp_srcid = p_vci_tgt.srcid.read(); |
1119 | | r_tgt_cmd_to_tgt_rsp_trdid = p_vci_tgt.trdid.read(); |
1120 | | r_tgt_cmd_to_tgt_rsp_pktid = p_vci_tgt.pktid.read(); |
1121 | | r_tgt_cmd_to_tgt_rsp_req = true; |
1122 | | r_tgt_cmd_to_tgt_rsp_error = error; |
1123 | | r_tgt_cmd_to_tgt_rsp_rdata = rdata; |
1124 | | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
1125 | | } |
1126 | | else |
1127 | | { |
1128 | | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
1129 | | } |
1130 | | |
1131 | | #if DEBUG_MEMC_TGT_CMD |
1132 | | if(m_debug) |
1133 | | std::cout << " <MEMC " << name() << " TGT_CMD_CONFIG> Configuration request:" |
1134 | | << " address = " << std::hex << p_vci_tgt.address.read() |
1135 | | << " / wdata = " << p_vci_tgt.wdata.read() |
1136 | | << " / need_rsp = " << need_rsp |
1137 | | << " / error = " << error << std::endl; |
1138 | | #endif |
1139 | | break; |
1140 | | } |
1141 | | ////////////////// |
1142 | | case TGT_CMD_READ: // Push a read request into read fifo |
1143 | | |
1144 | | // check that the read does not cross a cache line limit. |
1145 | | if ( ((m_x[(addr_t) p_vci_tgt.address.read()]+ (p_vci_tgt.plen.read() >>2)) > 16) and |
1146 | | (p_vci_tgt.cmd.read() != vci_param_int::CMD_LOCKED_READ)) |
1147 | | { |
1148 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" |
1149 | | << " illegal address/plen for VCI read command" << std::endl; |
1150 | | exit(0); |
1151 | | } |
1152 | | // check single flit |
1153 | | if(!p_vci_tgt.eop.read()) |
1154 | | { |
1155 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" |
1156 | | << " read command packet must contain one single flit" << std::endl; |
1157 | | exit(0); |
1158 | | } |
1159 | | // check plen for LL |
1160 | | if ( (p_vci_tgt.cmd.read() == vci_param_int::CMD_LOCKED_READ) and |
1161 | | (p_vci_tgt.plen.read() != 8) ) |
1162 | | { |
1163 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_READ state" |
1164 | | << " ll command packets must have a plen of 8" << std::endl; |
1165 | | exit(0); |
1166 | | } |
1167 | | |
1168 | | if ( p_vci_tgt.cmdval and m_cmd_read_addr_fifo.wok() ) |
1169 | | { |
1170 | | |
1171 | | #if DEBUG_MEMC_TGT_CMD |
1172 | | if(m_debug) |
1173 | | std::cout << " <MEMC " << name() << " TGT_CMD_READ> Push into read_fifo:" |
1174 | | << " address = " << std::hex << p_vci_tgt.address.read() |
1175 | | << " / srcid = " << p_vci_tgt.srcid.read() |
1176 | | << " / trdid = " << p_vci_tgt.trdid.read() |
1177 | | << " / pktid = " << p_vci_tgt.pktid.read() |
1178 | | << " / plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
1179 | | #endif |
1180 | | cmd_read_fifo_put = true; |
1181 | | if(p_vci_tgt.cmd.read() == vci_param_int::CMD_LOCKED_READ) m_cpt_ll++; |
1182 | | else m_cpt_read++; |
1183 | | r_tgt_cmd_fsm = TGT_CMD_IDLE; |
1184 | | } |
1185 | | break; |
1186 | | |
1187 | | /////////////////// |
1188 | | case TGT_CMD_WRITE: |
1189 | | if(p_vci_tgt.cmdval and m_cmd_write_addr_fifo.wok()) |
1190 | | { |
1191 | | |
1192 | | #if DEBUG_MEMC_TGT_CMD |
1193 | | if(m_debug) |
1194 | | std::cout << " <MEMC " << name() << " TGT_CMD_WRITE> Push into write_fifo:" |
1195 | | << " address = " << std::hex << p_vci_tgt.address.read() |
1196 | | << " / srcid = " << p_vci_tgt.srcid.read() |
1197 | | << " / trdid = " << p_vci_tgt.trdid.read() |
1198 | | << " / pktid = " << p_vci_tgt.pktid.read() |
1199 | | << " / wdata = " << p_vci_tgt.wdata.read() |
1200 | | << " / be = " << p_vci_tgt.be.read() |
1201 | | << " / plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
1202 | | #endif |
1203 | | cmd_write_fifo_put = true; |
1204 | | if(p_vci_tgt.eop) r_tgt_cmd_fsm = TGT_CMD_IDLE; |
1205 | | } |
1206 | | break; |
1207 | | |
1208 | | ///////////////// |
1209 | | case TGT_CMD_CAS: |
1210 | | if((p_vci_tgt.plen.read() != 8) and (p_vci_tgt.plen.read() != 16)) |
1211 | | { |
1212 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " TGT_CMD_CAS state" |
1213 | | << "illegal format for CAS command " << std::endl; |
1214 | | exit(0); |
1215 | | } |
1216 | | |
1217 | | if(p_vci_tgt.cmdval and m_cmd_cas_addr_fifo.wok()) |
1218 | | { |
1219 | | |
1220 | | #if DEBUG_MEMC_TGT_CMD |
1221 | | if(m_debug) |
1222 | | std::cout << " <MEMC " << name() << " TGT_CMD_CAS> Pushing command into cmd_cas_fifo:" |
1223 | | << " address = " << std::hex << p_vci_tgt.address.read() |
1224 | | << " srcid = " << p_vci_tgt.srcid.read() |
1225 | | << " trdid = " << p_vci_tgt.trdid.read() |
1226 | | << " pktid = " << p_vci_tgt.pktid.read() |
1227 | | << " wdata = " << p_vci_tgt.wdata.read() |
1228 | | << " be = " << p_vci_tgt.be.read() |
1229 | | << " plen = " << std::dec << p_vci_tgt.plen.read() << std::endl; |
1230 | | #endif |
1231 | | cmd_cas_fifo_put = true; |
1232 | | if(p_vci_tgt.eop) r_tgt_cmd_fsm = TGT_CMD_IDLE; |
1233 | | } |
1234 | | break; |
1235 | | } // end switch tgt_cmd_fsm |
1236 | | |
1237 | | ///////////////////////////////////////////////////////////////////////// |
1238 | | // MULTI_ACK FSM |
1239 | | ///////////////////////////////////////////////////////////////////////// |
1240 | | // This FSM controls the response to the multicast update requests sent |
1241 | | // by the memory cache to the L1 caches and update the UPT. |
1242 | | // |
1243 | | // - The FSM decrements the proper entry in UPT, |
1244 | | // and clear the UPT entry when all responses have been received. |
1245 | | // - If required, it sends a request to the TGT_RSP FSM to complete |
1246 | | // a pending write transaction. |
1247 | | // |
1248 | | // All those multi-ack packets are one flit packet. |
1249 | | // The index in the UPT is defined in the TRDID field. |
1250 | | //////////////////////////////////////////////////////////////////////// |
1251 | | |
1252 | | //std::cout << std::endl << "multi_ack_fsm" << std::endl; |
1253 | | |
1254 | | switch(r_multi_ack_fsm.read()) |
1255 | | { |
1256 | | //////////////////// |
1257 | | case MULTI_ACK_IDLE: |
1258 | | { |
1259 | | bool multi_ack_fifo_rok = m_cc_receive_to_multi_ack_fifo.rok(); |
1260 | | |
1261 | | // No CC_RECEIVE FSM request and no WRITE FSM request |
1262 | | if( not multi_ack_fifo_rok and not r_write_to_multi_ack_req.read()) |
1263 | | break; |
1264 | | |
1265 | | uint8_t updt_index; |
1266 | | |
1267 | | // handling WRITE FSM request to decrement update table response |
1268 | | // counter if no CC_RECEIVE FSM request |
1269 | | if(not multi_ack_fifo_rok) |
1270 | | { |
1271 | | updt_index = r_write_to_multi_ack_upt_index.read(); |
1272 | | r_write_to_multi_ack_req = false; |
1273 | | } |
1274 | | // Handling CC_RECEIVE FSM request |
1275 | | else |
1276 | | { |
1277 | | uint64_t flit = m_cc_receive_to_multi_ack_fifo.read(); |
1278 | | updt_index = DspinDhccpParam::dspin_get(flit, |
1279 | | DspinDhccpParam::MULTI_ACK_UPDT_INDEX); |
1280 | | |
1281 | | cc_receive_to_multi_ack_fifo_get = true; |
1282 | | } |
1283 | | |
1284 | | assert((updt_index < m_upt.size()) and |
1285 | | "VCI_MEM_CACHE ERROR in MULTI_ACK_IDLE : " |
1286 | | "index too large for UPT"); |
1287 | | |
1288 | | r_multi_ack_upt_index = updt_index; |
1289 | | r_multi_ack_fsm = MULTI_ACK_UPT_LOCK; |
1290 | | |
1291 | | #if DEBUG_MEMC_MULTI_ACK |
1292 | | if(m_debug) |
1293 | | { |
1294 | | if (multi_ack_fifo_rok) |
1295 | | { |
1296 | | std::cout << " <MEMC " << name() |
1297 | | << " MULTI_ACK_IDLE> Response for UPT entry " |
1298 | | << (size_t)updt_index << std::endl; |
1299 | | } |
1300 | | else |
1301 | | { |
1302 | | std::cout << " <MEMC " << name() |
1303 | | << " MULTI_ACK_IDLE> Write FSM request to decrement UPT entry " |
1304 | | << updt_index << std::endl; |
1305 | | } |
1306 | | } |
1307 | | #endif |
1308 | | break; |
1309 | | } |
1310 | | |
1311 | | //////////////////////// |
1312 | | case MULTI_ACK_UPT_LOCK: |
1313 | | { |
1314 | | // get lock to the UPDATE table |
1315 | | if(r_alloc_upt_fsm.read() != ALLOC_UPT_MULTI_ACK) break; |
1316 | | |
1317 | | // decrement the number of expected responses |
1318 | | size_t count = 0; |
1319 | | bool valid = m_upt.decrement(r_multi_ack_upt_index.read(), count); |
1320 | | |
1321 | | if(not valid) |
1322 | | { |
1323 | | std::cout << "VCI_MEM_CACHE ERROR " << name() |
1324 | | << " MULTI_ACK_UPT_LOCK state" << std::endl |
1325 | | << "unsuccessful access to decrement the UPT" << std::endl; |
1326 | | exit(0); |
1327 | | } |
1328 | | |
1329 | | if(count == 0) |
1330 | | { |
1331 | | r_multi_ack_fsm = MULTI_ACK_UPT_CLEAR; |
1332 | | } |
1333 | | else |
1334 | | { |
1335 | | r_multi_ack_fsm = MULTI_ACK_IDLE; |
1336 | | } |
1337 | | |
1338 | | #if DEBUG_MEMC_MULTI_ACK |
1339 | | if(m_debug) |
1340 | | std::cout << " <MEMC " << name() |
1341 | | << " MULTI_ACK_UPT_LOCK> Decrement the responses counter for UPT:" |
1342 | | << " entry = " << r_multi_ack_upt_index.read() |
1343 | | << " / rsp_count = " << std::dec << count << std::endl; |
1344 | | #endif |
1345 | | break; |
1346 | | } |
1347 | | |
1348 | | ///////////////////////// |
1349 | | case MULTI_ACK_UPT_CLEAR: // Clear UPT entry / Test if rsp or ack required |
1350 | | { |
1351 | | if(r_alloc_upt_fsm.read() != ALLOC_UPT_MULTI_ACK) |
1352 | | { |
1353 | | std::cout << "VCI_MEM_CACHE ERROR " << name() |
1354 | | << " MULTI_ACK_UPT_CLEAR state" |
1355 | | << " bad UPT allocation" << std::endl; |
1356 | | exit(0); |
1357 | | } |
1358 | | |
1359 | | r_multi_ack_srcid = m_upt.srcid(r_multi_ack_upt_index.read()); |
1360 | | r_multi_ack_trdid = m_upt.trdid(r_multi_ack_upt_index.read()); |
1361 | | r_multi_ack_pktid = m_upt.pktid(r_multi_ack_upt_index.read()); |
1362 | | r_multi_ack_nline = m_upt.nline(r_multi_ack_upt_index.read()); |
1363 | | bool need_rsp = m_upt.need_rsp(r_multi_ack_upt_index.read()); |
1364 | | |
1365 | | // clear the UPT entry |
1366 | | m_upt.clear(r_multi_ack_upt_index.read()); |
1367 | | |
1368 | | if ( need_rsp ) r_multi_ack_fsm = MULTI_ACK_WRITE_RSP; |
1369 | | else r_multi_ack_fsm = MULTI_ACK_IDLE; |
1370 | | |
1371 | | #if DEBUG_MEMC_MULTI_ACK |
1372 | | if(m_debug) |
1373 | | std::cout << " <MEMC " << name() |
1374 | | << " MULTI_ACK_UPT_CLEAR> Clear UPT entry " |
1375 | | << std::dec << r_multi_ack_upt_index.read() << std::endl; |
1376 | | #endif |
1377 | | break; |
1378 | | } |
1379 | | ///////////////////////// |
1380 | | case MULTI_ACK_WRITE_RSP: // Post a response request to TGT_RSP FSM |
1381 | | // Wait if pending request |
1382 | | { |
1383 | | if ( r_multi_ack_to_tgt_rsp_req.read() ) break; |
1384 | | |
1385 | | r_multi_ack_to_tgt_rsp_req = true; |
1386 | | r_multi_ack_to_tgt_rsp_srcid = r_multi_ack_srcid.read(); |
1387 | | r_multi_ack_to_tgt_rsp_trdid = r_multi_ack_trdid.read(); |
1388 | | r_multi_ack_to_tgt_rsp_pktid = r_multi_ack_pktid.read(); |
1389 | | r_multi_ack_fsm = MULTI_ACK_IDLE; |
1390 | | |
1391 | | #if DEBUG_MEMC_MULTI_ACK |
1392 | | if(m_debug) |
1393 | | std::cout << " <MEMC " << name() << " MULTI_ACK_WRITE_RSP>" |
1394 | | << " Request TGT_RSP FSM to send a response to srcid " |
1395 | | << std::hex << r_multi_ack_srcid.read() << std::endl; |
1396 | | #endif |
1397 | | break; |
1398 | | } |
1399 | | } // end switch r_multi_ack_fsm |
1400 | | |
1401 | | //////////////////////////////////////////////////////////////////////////////////// |
1402 | | // CONFIG FSM |
1403 | | //////////////////////////////////////////////////////////////////////////////////// |
1404 | | // The CONFIG FSM handles the VCI configuration requests (INVAL & SYNC). |
1405 | | // The target buffer can have any size, and there is one single command for |
1406 | | // all cache lines covered by the target buffer. |
1407 | | // |
1408 | | // An INVAL or SYNC configuration operation is defined by the following registers: |
1409 | | // - bool r_config_cmd : INVAL / SYNC / NOP |
1410 | | // - uint64_t r_config_address : buffer base address |
1411 | | // - uint32_t r_config_cmd_lines : number of lines to be handled |
1412 | | // - uint32_t r_config_rsp_lines : number of lines not completed |
1413 | | // |
1414 | | // For both INVAL and SYNC commands, the CONFIG FSM contains the loop handling |
1415 | | // all cache lines covered by the buffer. The various lines of a given buffer |
1416 | | // can be pipelined: the CONFIG FSM does not wait the response for line (n) to send |
1417 | | // the command for line (n+1). It decrements the r_config_cmd_lines counter until |
1418 | | // the last request has been registered in TRT (for a SYNC), or in IVT (for an INVAL). |
1419 | | // |
1420 | | // - INVAL request: |
1421 | | // For each line, it access to the DIR. |
1422 | | // In case of miss, it does nothing, and a response is requested to TGT_RSP FSM. |
1423 | | // In case of hit, with no copies in L1 caches, the line is invalidated and |
1424 | | // a response is requested to TGT_RSP FSM. |
1425 | | // If there is copies, a multi-inval, or a broadcast-inval coherence transaction |
1426 | | // is launched and registered in UPT. The multi-inval transaction completion |
1427 | | // is signaled by the CLEANUP FSM by decrementing the r_config_rsp_lines counter. |
1428 | | // The CONFIG INVAL response is sent only when the last line has been invalidated. |
1429 | | // TODO : The target buffer address must be aligned on a cache line boundary. |
1430 | | // This constraint can be released, but it requires to make 2 PUT transactions |
1431 | | // for the first and the last line... |
1432 | | // |
1433 | | // - SYNC request: |
1434 | | // For each line, it access to the DIR. |
1435 | | // In case of miss, it does nothing, and a response is requested to TGT_RSP FSM. |
1436 | | // In case of hit, a PUT transaction is registered in TRT and a request is sent |
1437 | | // to IXR_CMD FSM. The IXR_RSP FSM decrements the r_config_rsp_lines counter |
1438 | | // when a PUT response is received. |
1439 | | // The CONFIG SYNC response is sent only when the last PUT response is received. |
1440 | | // |
1441 | | // From the software point of view, a configuration request is a sequence |
1442 | | // of 6 atomic accesses in an uncached segment. A dedicated lock is used |
1443 | | // to handle only one configuration command at a given time: |
1444 | | // - Read MEMC_LOCK : Get the lock |
1445 | | // - Write MEMC_ADDR_LO : Set the buffer address LSB |
1446 | | // - Write MEMC_ADDR_HI : Set the buffer address MSB |
1447 | | // - Write MEMC_BUF_LENGTH : set buffer length (bytes) |
1448 | | // - Write MEMC_CMD_TYPE : launch the actual operation |
1449 | | // - WRITE MEMC_LOCK : release the lock |
1450 | | //////////////////////////////////////////////////////////////////////////////////// |
1451 | | |
1452 | | //std::cout << std::endl << "config_fsm" << std::endl; |
1453 | | |
1454 | | switch( r_config_fsm.read() ) |
1455 | | { |
1456 | | ///////////////// |
1457 | | case CONFIG_IDLE: // waiting a config request |
1458 | | { |
1459 | | if ( r_config_cmd.read() != MEMC_CMD_NOP ) |
1460 | | { |
1461 | | r_config_fsm = CONFIG_LOOP; |
1462 | | |
1463 | | #if DEBUG_MEMC_CONFIG |
1464 | | if(m_debug) |
1465 | | std::cout << " <MEMC " << name() << " CONFIG_IDLE> Config Request received" |
1466 | | << " / address = " << std::hex << r_config_address.read() |
1467 | | << " / lines = " << std::dec << r_config_cmd_lines.read() |
1468 | | << " / type = " << r_config_cmd.read() << std::endl; |
1469 | | #endif |
1470 | | } |
1471 | | break; |
1472 | | } |
1473 | | ///////////////// |
1474 | | case CONFIG_LOOP: // test if last line to be handled |
1475 | | { |
1476 | | if ( r_config_cmd_lines.read() == 0 ) |
1477 | | { |
1478 | | r_config_cmd = MEMC_CMD_NOP; |
1479 | | r_config_fsm = CONFIG_WAIT; |
1480 | | } |
1481 | | else |
1482 | | { |
1483 | | r_config_fsm = CONFIG_DIR_REQ; |
1484 | | } |
1485 | | |
1486 | | #if DEBUG_MEMC_CONFIG |
1487 | | if(m_debug) |
1488 | | std::cout << " <MEMC " << name() << " CONFIG_LOOP>" |
1489 | | << " / address = " << std::hex << r_config_address.read() |
1490 | | << " / lines not handled = " << std::dec << r_config_cmd_lines.read() |
1491 | | << " / command = " << r_config_cmd.read() << std::endl; |
1492 | | #endif |
1493 | | break; |
1494 | | } |
1495 | | ///////////////// |
1496 | | case CONFIG_WAIT: // wait completion (last response) |
1497 | | { |
1498 | | if ( r_config_rsp_lines.read() == 0 ) // last response received |
1499 | | { |
1500 | | r_config_fsm = CONFIG_RSP; |
1501 | | } |
1502 | | |
1503 | | #if DEBUG_MEMC_CONFIG |
1504 | | if(m_debug) |
1505 | | std::cout << " <MEMC " << name() << " CONFIG_WAIT>" |
1506 | | << " / lines to do = " << std::dec << r_config_rsp_lines.read() << std::endl; |
1507 | | #endif |
1508 | | break; |
1509 | | } |
1510 | | //////////////// |
1511 | | case CONFIG_RSP: // request TGT_RSP FSM to return response |
1512 | | { |
1513 | | if ( not r_config_to_tgt_rsp_req.read() ) |
1514 | | { |
1515 | | r_config_to_tgt_rsp_srcid = r_config_srcid.read(); |
1516 | | r_config_to_tgt_rsp_trdid = r_config_trdid.read(); |
1517 | | r_config_to_tgt_rsp_pktid = r_config_pktid.read(); |
1518 | | r_config_to_tgt_rsp_error = false; |
1519 | | r_config_to_tgt_rsp_req = true; |
1520 | | r_config_fsm = CONFIG_IDLE; |
1521 | | |
1522 | | #if DEBUG_MEMC_CONFIG |
1523 | | if(m_debug) |
1524 | | std::cout << " <MEMC " << name() << " CONFIG_RSP> Request TGT_RSP FSM to return response:" |
1525 | | << " error = " << r_config_to_tgt_rsp_error.read() |
1526 | | << " / rsrcid = " << std::hex << r_config_srcid.read() |
1527 | | << " / rtrdid = " << std::hex << r_config_trdid.read() |
1528 | | << " / rpktid = " << std::hex << r_config_pktid.read() << std::endl; |
1529 | | #endif |
1530 | | } |
1531 | | break; |
1532 | | |
1533 | | } |
1534 | | //////////////////// |
1535 | | case CONFIG_DIR_REQ: // Request directory lock |
1536 | | { |
1537 | | if ( r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG ) |
1538 | | { |
1539 | | r_config_fsm = CONFIG_DIR_ACCESS; |
1540 | | } |
1541 | | |
1542 | | #if DEBUG_MEMC_CONFIG |
1543 | | if(m_debug) |
1544 | | std::cout << " <MEMC " << name() << " CONFIG_DIR_REQ>" |
1545 | | << " Request DIR access" << std::endl; |
1546 | | #endif |
1547 | | break; |
1548 | | } |
1549 | | /////////////////////// |
1550 | | case CONFIG_DIR_ACCESS: // Access directory and decode config command |
1551 | | { |
1552 | | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
1553 | | "MEMC ERROR in CONFIG_DIR_ACCESS state: bad DIR allocation"); |
1554 | | |
1555 | | size_t way = 0; |
1556 | | DirectoryEntry entry = m_cache_directory.read(r_config_address.read(), way); |
1557 | | |
1558 | | r_config_dir_way = way; |
1559 | | r_config_dir_copy_inst = entry.owner.inst; |
1560 | | r_config_dir_copy_srcid = entry.owner.srcid; |
1561 | | r_config_dir_is_cnt = entry.is_cnt; |
1562 | | r_config_dir_lock = entry.lock; |
1563 | | r_config_dir_count = entry.count; |
1564 | | r_config_dir_ptr = entry.ptr; |
1565 | | |
1566 | | if ( entry.valid and // hit & inval command |
1567 | | (r_config_cmd.read() == MEMC_CMD_INVAL) ) |
1568 | | { |
1569 | | r_config_fsm = CONFIG_IVT_LOCK; |
1570 | | } |
1571 | | else if ( entry.valid and // hit & sync command |
1572 | | entry.dirty and |
1573 | | (r_config_cmd.read() == MEMC_CMD_SYNC) ) |
1574 | | { |
1575 | | r_config_fsm = CONFIG_TRT_LOCK; |
1576 | | } |
1577 | | else // miss : return to LOOP |
1578 | | { |
1579 | | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
1580 | | r_config_rsp_lines = r_config_rsp_lines.read() - 1; |
1581 | | r_config_address = r_config_address.read() + (m_words<<2); |
1582 | | r_config_fsm = CONFIG_LOOP; |
1583 | | } |
1584 | | |
1585 | | #if DEBUG_MEMC_CONFIG |
1586 | | if(m_debug) |
1587 | | std::cout << " <MEMC " << name() << " CONFIG_DIR_ACCESS> Accessing directory: " |
1588 | | << " address = " << std::hex << r_config_address.read() |
1589 | | << " / hit = " << std::dec << entry.valid |
1590 | | << " / dirty = " << entry.dirty |
1591 | | << " / count = " << entry.count |
1592 | | << " / is_cnt = " << entry.is_cnt << std::endl; |
1593 | | #endif |
1594 | | break; |
1595 | | } |
1596 | | ///////////////////// |
1597 | | case CONFIG_TRT_LOCK: // enter this state in case of SYNC command |
1598 | | // to a dirty cache line |
1599 | | // keep DIR lock, and try to get TRT lock |
1600 | | // return to LOOP state if TRT full |
1601 | | // reset dirty bit in DIR and register a PUT |
1602 | | // trabsaction in TRT if not full. |
1603 | | { |
1604 | | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
1605 | | "MEMC ERROR in CONFIG_TRT_LOCK state: bad DIR allocation"); |
1606 | | |
1607 | | if ( r_alloc_trt_fsm.read() == ALLOC_TRT_CONFIG ) |
1608 | | { |
1609 | | size_t index = 0; |
1610 | | bool wok = not m_trt.full(index); |
1611 | | |
1612 | | if ( not wok ) |
1613 | | { |
1614 | | r_config_fsm = CONFIG_LOOP; |
1615 | | } |
1616 | | else |
1617 | | { |
1618 | | size_t way = r_config_dir_way.read(); |
1619 | | size_t set = m_y[r_config_address.read()]; |
1620 | | |
1621 | | // reset dirty bit in DIR |
1622 | | DirectoryEntry entry; |
1623 | | entry.valid = true; |
1624 | | entry.dirty = false; |
1625 | | entry.tag = m_z[r_config_address.read()]; |
1626 | | entry.is_cnt = r_config_dir_is_cnt.read(); |
1627 | | entry.lock = r_config_dir_lock.read(); |
1628 | | entry.ptr = r_config_dir_ptr.read(); |
1629 | | entry.count = r_config_dir_count.read(); |
1630 | | entry.owner.inst = r_config_dir_copy_inst.read(); |
1631 | | entry.owner.srcid = r_config_dir_copy_srcid.read(); |
1632 | | m_cache_directory.write( set, way, entry ); |
1633 | | |
1634 | | r_config_trt_index = index; |
1635 | | r_config_fsm = CONFIG_TRT_SET; |
1636 | | } |
1637 | | |
1638 | | #if DEBUG_MEMC_CONFIG |
1639 | | if(m_debug) |
1640 | | std::cout << " <MEMC " << name() << " CONFIG_TRT_LOCK> Access TRT: " |
1641 | | << " wok = " << std::dec << wok |
1642 | | << " index = " << index << std::endl; |
1643 | | #endif |
1644 | | } |
1645 | | break; |
1646 | | } |
1647 | | //////////////////// |
1648 | | case CONFIG_TRT_SET: // read data in cache |
1649 | | // and post a PUT request in TRT |
1650 | | { |
1651 | | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
1652 | | "MEMC ERROR in CONFIG_TRT_SET state: bad DIR allocation"); |
1653 | | |
1654 | | assert( (r_alloc_trt_fsm.read() == ALLOC_TRT_CONFIG) and |
1655 | | "MEMC ERROR in CONFIG_TRT_SET state: bad TRT allocation"); |
1656 | | |
1657 | | // read data into cache |
1658 | | size_t way = r_config_dir_way.read(); |
1659 | | size_t set = m_y[r_config_address.read()]; |
1660 | | std::vector<data_t> data_vector; |
1661 | | data_vector.clear(); |
1662 | | for(size_t word=0; word<m_words; word++) |
1663 | | { |
1664 | | uint32_t data = m_cache_data.read( way, set, word ); |
1665 | | data_vector.push_back( data ); |
1666 | | } |
1667 | | |
1668 | | // post the PUT request in TRT |
1669 | | m_trt.set( r_config_trt_index.read(), |
1670 | | false, // PUT transaction |
1671 | | m_nline[r_config_address.read()], // line index |
1672 | | 0, // srcid: unused |
1673 | | 0, // trdid: unused |
1674 | | 0, // pktid: unused |
1675 | | false, // not proc_read |
1676 | | 0, // read_length: unused |
1677 | | 0, // word_index: unused |
1678 | | std::vector<be_t>(m_words,0xF), // byte-enable: unused |
1679 | | data_vector, // data to be written |
1680 | | 0, // ll_key: unused |
1681 | | true ); // requested by config FSM |
1682 | | r_config_fsm = CONFIG_PUT_REQ; |
1683 | | |
1684 | | #if DEBUG_MEMC_CONFIG |
1685 | | if(m_debug) |
1686 | | std::cout << " <MEMC " << name() << " CONFIG_TRT_SET> PUT request in TRT:" |
1687 | | << " address = " << std::hex << r_config_address.read() |
1688 | | << " index = " << std::dec << r_config_trt_index.read() << std::endl; |
1689 | | #endif |
1690 | | break; |
1691 | | } |
1692 | | //////////////////// |
1693 | | case CONFIG_PUT_REQ: // post PUT request to IXR_CMD_FSM |
1694 | | { |
1695 | | if ( not r_config_to_ixr_cmd_req.read() ) |
1696 | | { |
1697 | | r_config_to_ixr_cmd_req = true; |
1698 | | r_config_to_ixr_cmd_index = r_config_trt_index.read(); |
1699 | | |
1700 | | // prepare next iteration |
1701 | | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
1702 | | r_config_address = r_config_address.read() + (m_words<<2); |
1703 | | r_config_fsm = CONFIG_LOOP; |
1704 | | |
1705 | | #if DEBUG_MEMC_CONFIG |
1706 | | if(m_debug) |
1707 | | std::cout << " <MEMC " << name() << " CONFIG_PUT_REQ> post PUT request to IXR_CMD_FSM" |
1708 | | << " / address = " << std::hex << r_config_address.read() << std::endl; |
1709 | | #endif |
1710 | | } |
1711 | | break; |
1712 | | } |
1713 | | ///////////////////// |
1714 | | case CONFIG_IVT_LOCK: // enter this state in case of INVAL command |
1715 | | // Keep DIR lock and Try to get IVT lock. |
1716 | | // Return to LOOP state if IVT full. |
1717 | | // Register inval in IVT, and invalidate the |
1718 | | // directory if IVT not full. |
1719 | | { |
1720 | | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_CONFIG) and |
1721 | | "MEMC ERROR in CONFIG_IVT_LOCK state: bad DIR allocation"); |
1722 | | |
1723 | | if ( r_alloc_ivt_fsm.read() == ALLOC_IVT_CONFIG ) |
1724 | | { |
1725 | | size_t set = m_y[(addr_t)(r_config_address.read())]; |
1726 | | size_t way = r_config_dir_way.read(); |
1727 | | |
1728 | | if ( r_config_dir_count.read() == 0 ) // inval DIR and return to LOOP |
1729 | | { |
1730 | | m_cache_directory.inval( way, set ); |
1731 | | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
1732 | | r_config_rsp_lines = r_config_rsp_lines.read() - 1; |
1733 | | r_config_address = r_config_address.read() + (m_words<<2); |
1734 | | r_config_fsm = CONFIG_LOOP; |
1735 | | |
1736 | | #if DEBUG_MEMC_CONFIG |
1737 | | if(m_debug) |
1738 | | std::cout << " <MEMC " << name() << " CONFIG_IVT_LOCK>" |
1739 | | << " No copies in L1 : inval DIR entry" << std::endl; |
1740 | | #endif |
1741 | | } |
1742 | | else // try to register inval in IVT |
1743 | | { |
1744 | | bool wok = false; |
1745 | | size_t index = 0; |
1746 | | bool broadcast = r_config_dir_is_cnt.read(); |
1747 | | size_t srcid = r_config_srcid.read(); |
1748 | | size_t trdid = r_config_trdid.read(); |
1749 | | size_t pktid = r_config_pktid.read(); |
1750 | | addr_t nline = m_nline[(addr_t)(r_config_address.read())]; |
1751 | | size_t nb_copies = r_config_dir_count.read(); |
1752 | | |
1753 | | wok = m_ivt.set(false, // it's an inval transaction |
1754 | | broadcast, |
1755 | | false, // no response required |
1756 | | true, // acknowledge required |
1757 | | srcid, |
1758 | | trdid, |
1759 | | pktid, |
1760 | | nline, |
1761 | | nb_copies, |
1762 | | index); |
1763 | | |
1764 | | if ( wok ) // IVT success => inval DIR slot |
1765 | | { |
1766 | | m_cache_directory.inval( way, set ); |
1767 | | r_config_ivt_index = index; |
1768 | | if ( broadcast ) r_config_fsm = CONFIG_BC_SEND; |
1769 | | else r_config_fsm = CONFIG_INVAL_SEND; |
1770 | | |
1771 | | #if DEBUG_MEMC_CONFIG |
1772 | | if(m_debug) |
1773 | | std::cout << " <MEMC " << name() << " CONFIG_IVT_LOCK>" |
1774 | | << " Inval DIR entry and register inval in IVT" |
1775 | | << " / index = " << std::dec << index |
1776 | | << " / broadcast = " << broadcast << std::endl; |
1777 | | #endif |
1778 | | } |
1779 | | else // IVT full => release both DIR and IVT locks |
1780 | | { |
1781 | | r_config_fsm = CONFIG_LOOP; |
1782 | | |
1783 | | #if DEBUG_MEMC_CONFIG |
1784 | | if(m_debug) |
1785 | | std::cout << " <MEMC " << name() << " CONFIG_IVT_LOCK>" |
1786 | | << " IVT full : release DIR & IVT locks and retry" << std::endl; |
1787 | | #endif |
1788 | | } |
1789 | | } |
1790 | | } |
1791 | | break; |
1792 | | } |
1793 | | //////////////////// |
1794 | | case CONFIG_BC_SEND: // Post a broadcast inval request to CC_SEND FSM |
1795 | | { |
1796 | | if( not r_config_to_cc_send_multi_req.read() and |
1797 | | not r_config_to_cc_send_brdcast_req.read() ) |
1798 | | { |
1799 | | // post bc inval request |
1800 | | r_config_to_cc_send_multi_req = false; |
1801 | | r_config_to_cc_send_brdcast_req = true; |
1802 | | r_config_to_cc_send_trdid = r_config_ivt_index.read(); |
1803 | | r_config_to_cc_send_nline = m_nline[(addr_t)(r_config_address.read())]; |
1804 | | |
1805 | | // prepare next iteration |
1806 | | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
1807 | | r_config_address = r_config_address.read() + (m_words<<2); |
1808 | | r_config_fsm = CONFIG_LOOP; |
1809 | | |
1810 | | #if DEBUG_MEMC_CONFIG |
1811 | | if(m_debug) |
1812 | | std::cout << " <MEMC " << name() << " CONFIG_BC_SEND>" |
1813 | | << " Post a broadcast inval request to CC_SEND FSM" |
1814 | | << " / address = " << r_config_address.read() <<std::endl; |
1815 | | #endif |
1816 | | } |
1817 | | break; |
1818 | | } |
1819 | | /////////////////////// |
1820 | | case CONFIG_INVAL_SEND: // Post a multi inval request to CC_SEND FSM |
1821 | | { |
1822 | | if( not r_config_to_cc_send_multi_req.read() and |
1823 | | not r_config_to_cc_send_brdcast_req.read() ) |
1824 | | { |
1825 | | // post multi inval request |
1826 | | r_config_to_cc_send_multi_req = true; |
1827 | | r_config_to_cc_send_brdcast_req = false; |
1828 | | r_config_to_cc_send_trdid = r_config_ivt_index.read(); |
1829 | | r_config_to_cc_send_nline = m_nline[(addr_t)(r_config_address.read())]; |
1830 | | |
1831 | | // post data into FIFO |
1832 | | config_to_cc_send_fifo_srcid = r_config_dir_copy_srcid.read(); |
1833 | | config_to_cc_send_fifo_inst = r_config_dir_copy_inst.read(); |
1834 | | config_to_cc_send_fifo_put = true; |
1835 | | |
1836 | | if ( r_config_dir_count.read() == 1 ) // one copy |
1837 | | { |
1838 | | // prepare next iteration |
1839 | | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
1840 | | r_config_address = r_config_address.read() + (m_words<<2); |
1841 | | r_config_fsm = CONFIG_LOOP; |
1842 | | } |
1843 | | else // several copies |
1844 | | { |
1845 | | r_config_fsm = CONFIG_HEAP_REQ; |
1846 | | } |
1847 | | |
1848 | | #if DEBUG_MEMC_CONFIG |
1849 | | if(m_debug) |
1850 | | std::cout << " <MEMC " << name() << " CONFIG_INVAL_SEND>" |
1851 | | << " Post multi inval request to CC_SEND FSM" |
1852 | | << " / address = " << std::hex << r_config_address.read() |
1853 | | << " / copy = " << r_config_dir_copy_srcid.read() |
1854 | | << " / inst = " << std::dec << r_config_dir_copy_inst.read() << std::endl; |
1855 | | #endif |
1856 | | } |
1857 | | break; |
1858 | | } |
1859 | | ///////////////////// |
1860 | | case CONFIG_HEAP_REQ: // Try to get access to Heap |
1861 | | { |
1862 | | if ( r_alloc_heap_fsm.read() == ALLOC_HEAP_CONFIG ) |
1863 | | { |
1864 | | r_config_fsm = CONFIG_HEAP_SCAN; |
1865 | | r_config_heap_next = r_config_dir_ptr.read(); |
1866 | | } |
1867 | | |
1868 | | #if DEBUG_MEMC_CONFIG |
1869 | | if(m_debug) |
1870 | | std::cout << " <MEMC " << name() << " CONFIG_HEAP_REQ>" |
1871 | | << " Requesting HEAP lock" << std::endl; |
1872 | | #endif |
1873 | | break; |
1874 | | } |
1875 | | ////////////////////// |
1876 | | case CONFIG_HEAP_SCAN: // scan HEAP and send inval to CC_SEND FSM |
1877 | | { |
1878 | | HeapEntry entry = m_heap.read( r_config_heap_next.read() ); |
1879 | | bool last_copy = (entry.next == r_config_heap_next.read()); |
1880 | | |
1881 | | config_to_cc_send_fifo_srcid = entry.owner.srcid; |
1882 | | config_to_cc_send_fifo_inst = entry.owner.inst; |
1883 | | // config_to_cc_send_fifo_last = last_copy; |
1884 | | config_to_cc_send_fifo_put = true; |
1885 | | |
1886 | | if ( m_config_to_cc_send_inst_fifo.wok() ) // inval request accepted |
1887 | | { |
1888 | | r_config_heap_next = entry.next; |
1889 | | if ( last_copy ) r_config_fsm = CONFIG_HEAP_LAST; |
1890 | | } |
1891 | | |
1892 | | #if DEBUG_MEMC_CONFIG |
1893 | | if(m_debug) |
1894 | | std::cout << " <MEMC " << name() << " CONFIG_HEAP_SCAN>" |
1895 | | << " Post multi inval request to CC_SEND FSM" |
1896 | | << " / address = " << std::hex << r_config_address.read() |
1897 | | << " / copy = " << entry.owner.srcid |
1898 | | << " / inst = " << std::dec << entry.owner.inst << std::endl; |
1899 | | #endif |
1900 | | break; |
1901 | | } |
1902 | | ////////////////////// |
1903 | | case CONFIG_HEAP_LAST: // HEAP housekeeping |
1904 | | { |
1905 | | size_t free_pointer = m_heap.next_free_ptr(); |
1906 | | HeapEntry last_entry; |
1907 | | last_entry.owner.srcid = 0; |
1908 | | last_entry.owner.inst = false; |
1909 | | |
1910 | | if ( m_heap.is_full() ) |
1911 | | { |
1912 | | last_entry.next = r_config_dir_ptr.read(); |
1913 | | m_heap.unset_full(); |
1914 | | } |
1915 | | else |
1916 | | { |
1917 | | last_entry.next = free_pointer; |
1918 | | } |
1919 | | |
1920 | | m_heap.write_free_ptr( r_config_dir_ptr.read() ); |
1921 | | m_heap.write( r_config_heap_next.read(), last_entry ); |
1922 | | |
1923 | | // prepare next iteration |
1924 | | r_config_cmd_lines = r_config_cmd_lines.read() - 1; |
1925 | | r_config_address = r_config_address.read() + (m_words<<2); |
1926 | | r_config_fsm = CONFIG_LOOP; |
1927 | | |
1928 | | #if DEBUG_MEMC_CONFIG |
1929 | | if(m_debug) |
1930 | | std::cout << " <MEMC " << name() << " CONFIG_HEAP_LAST>" |
1931 | | << " Heap housekeeping" << std::endl; |
1932 | | #endif |
1933 | | break; |
1934 | | } |
1935 | | } // end switch r_config_fsm |
1936 | | |
1937 | | //////////////////////////////////////////////////////////////////////////////////// |
1938 | | // READ FSM |
1939 | | //////////////////////////////////////////////////////////////////////////////////// |
1940 | | // The READ FSM controls the VCI read and ll requests. |
1941 | | // It takes the lock protecting the cache directory to check the cache line status: |
1942 | | // - In case of HIT |
1943 | | // The fsm copies the data (one line, or one single word) |
1944 | | // in the r_read_to_tgt_rsp buffer. It waits if this buffer is not empty. |
1945 | | // The requesting initiator is registered in the cache directory. |
1946 | | // If the number of copy is larger than 1, the new copy is registered |
1947 | | // in the HEAP. |
1948 | | // If the number of copy is larger than the threshold, the HEAP is cleared, |
1949 | | // and the corresponding line switches to the counter mode. |
1950 | | // - In case of MISS |
1951 | | // The READ fsm takes the lock protecting the transaction tab. |
1952 | | // If a read transaction to the XRAM for this line already exists, |
1953 | | // or if the transaction tab is full, the fsm is stalled. |
1954 | | // If a TRT entry is free, the READ request is registered in TRT, |
1955 | | // it is consumed in the request FIFO, and transmited to the IXR_CMD FSM. |
1956 | | // The READ FSM returns in the IDLE state as the read transaction will be |
1957 | | // completed when the missing line will be received. |
1958 | | //////////////////////////////////////////////////////////////////////////////////// |
1959 | | |
1960 | | //std::cout << std::endl << "read_fsm" << std::endl; |
1961 | | |
1962 | | switch(r_read_fsm.read()) |
1963 | | { |
1964 | | /////////////// |
1965 | | case READ_IDLE: // waiting a read request |
1966 | | { |
1967 | | if(m_cmd_read_addr_fifo.rok()) |
1968 | | { |
1969 | | |
1970 | | #if DEBUG_MEMC_READ |
1971 | | if(m_debug) |
1972 | | std::cout << " <MEMC " << name() << " READ_IDLE> Read request" |
1973 | | << " : address = " << std::hex << m_cmd_read_addr_fifo.read() |
1974 | | << " / srcid = " << m_cmd_read_srcid_fifo.read() |
1975 | | << " / trdid = " << m_cmd_read_trdid_fifo.read() |
1976 | | << " / pktid = " << m_cmd_read_pktid_fifo.read() |
1977 | | << " / nwords = " << std::dec << m_cmd_read_length_fifo.read() << std::endl; |
1978 | | #endif |
1979 | | r_read_fsm = READ_DIR_REQ; |
1980 | | } |
1981 | | break; |
1982 | | } |
1983 | | ////////////////// |
1984 | | case READ_DIR_REQ: // Get the lock to the directory |
1985 | | { |
1986 | | if(r_alloc_dir_fsm.read() == ALLOC_DIR_READ) |
1987 | | { |
1988 | | r_read_fsm = READ_DIR_LOCK; |
1989 | | } |
1990 | | |
1991 | | #if DEBUG_MEMC_READ |
1992 | | if(m_debug) |
1993 | | std::cout << " <MEMC " << name() << " READ_DIR_REQ> Requesting DIR lock " << std::endl; |
1994 | | #endif |
1995 | | break; |
1996 | | } |
1997 | | |
1998 | | /////////////////// |
1999 | | case READ_DIR_LOCK: // check directory for hit / miss |
2000 | | { |
2001 | | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_READ) and |
2002 | | "MEMC ERROR in READ_DIR_LOCK state: Bad DIR allocation"); |
2003 | | |
2004 | | size_t way = 0; |
2005 | | DirectoryEntry entry = m_cache_directory.read(m_cmd_read_addr_fifo.read(), way); |
2006 | | |
2007 | | // access the global table ONLY when we have an LL cmd |
2008 | | if((m_cmd_read_pktid_fifo.read() & 0x7) == TYPE_LL) |
2009 | | { |
2010 | | r_read_ll_key = m_llsc_table.ll(m_cmd_read_addr_fifo.read()); |
2011 | | } |
2012 | | r_read_is_cnt = entry.is_cnt; |
2013 | | r_read_dirty = entry.dirty; |
2014 | | r_read_lock = entry.lock; |
2015 | | r_read_tag = entry.tag; |
2016 | | r_read_way = way; |
2017 | | r_read_count = entry.count; |
2018 | | r_read_copy = entry.owner.srcid; |
2019 | | r_read_copy_inst = entry.owner.inst; |
2020 | | r_read_ptr = entry.ptr; // pointer to the heap |
2021 | | |
2022 | | // check if this is a cached read, this means pktid is either |
2023 | | // TYPE_READ_DATA_MISS 0bX001 with TSAR encoding |
2024 | | // TYPE_READ_INS_MISS 0bX011 with TSAR encoding |
2025 | | bool cached_read = (m_cmd_read_pktid_fifo.read() & 0x1); |
2026 | | if(entry.valid) // hit |
2027 | | { |
2028 | | // test if we need to register a new copy in the heap |
2029 | | if(entry.is_cnt or (entry.count == 0) or !cached_read) |
2030 | | { |
2031 | | r_read_fsm = READ_DIR_HIT; |
2032 | | } |
2033 | | else |
2034 | | { |
2035 | | r_read_fsm = READ_HEAP_REQ; |
2036 | | } |
2037 | | } |
2038 | | else // miss |
2039 | | { |
2040 | | r_read_fsm = READ_TRT_LOCK; |
2041 | | } |
2042 | | |
2043 | | #if DEBUG_MEMC_READ |
2044 | | if(m_debug) |
2045 | | { |
2046 | | std::cout << " <MEMC " << name() << " READ_DIR_LOCK> Accessing directory: " |
2047 | | << " address = " << std::hex << m_cmd_read_addr_fifo.read() |
2048 | | << " / hit = " << std::dec << entry.valid |
2049 | | << " / count = " <<std::dec << entry.count |
2050 | | << " / is_cnt = " << entry.is_cnt; |
2051 | | if((m_cmd_read_pktid_fifo.read() & 0x7) == TYPE_LL) std::cout << " / LL access" << std::endl; |
2052 | | else std::cout << std::endl; |
2053 | | } |
2054 | | #endif |
2055 | | break; |
2056 | | } |
2057 | | ////////////////// |
2058 | | case READ_DIR_HIT: // read data in cache & update the directory |
2059 | | // we enter this state in 3 cases: |
2060 | | // - the read request is uncachable |
2061 | | // - the cache line is in counter mode |
2062 | | // - the cache line is valid but not replicated |
2063 | | |
2064 | | { |
2065 | | assert( (r_alloc_dir_fsm.read() == ALLOC_DIR_READ) and |
2066 | | "MEMC ERROR in READ_DIR_HIT state: Bad DIR allocation"); |
2067 | | |
2068 | | // check if this is an instruction read, this means pktid is either |
2069 | | // TYPE_READ_INS_UNC 0bX010 with TSAR encoding |
2070 | | // TYPE_READ_INS_MISS 0bX011 with TSAR encoding |
2071 | | bool inst_read = ((m_cmd_read_pktid_fifo.read() & 0x2) != 0); |
2072 | | // check if this is a cached read, this means pktid is either |
2073 | | // TYPE_READ_DATA_MISS 0bX001 with TSAR encoding |
2074 | | // TYPE_READ_INS_MISS 0bX011 with TSAR encoding |
2075 | | bool cached_read = (m_cmd_read_pktid_fifo.read() & 0x1); |
2076 | | bool is_cnt = r_read_is_cnt.read(); |
2077 | | |
2078 | | // read data in the cache |
2079 | | size_t set = m_y[(addr_t)(m_cmd_read_addr_fifo.read())]; |
2080 | | size_t way = r_read_way.read(); |
2081 | | |
2082 | | m_cache_data.read_line(way, set, r_read_data); |
2083 | | |
2084 | | // update the cache directory |
2085 | | DirectoryEntry entry; |
2086 | | entry.valid = true; |
2087 | | entry.is_cnt = is_cnt; |
2088 | | entry.dirty = r_read_dirty.read(); |
2089 | | entry.tag = r_read_tag.read(); |
2090 | | entry.lock = r_read_lock.read(); |
2091 | | entry.ptr = r_read_ptr.read(); |
2092 | | |
2093 | | if(cached_read) // Cached read => we must update the copies |
2094 | | { |
2095 | | if(!is_cnt) // Not counter mode |
2096 | | { |
2097 | | entry.owner.srcid = m_cmd_read_srcid_fifo.read(); |
2098 | | entry.owner.inst = inst_read; |
2099 | | entry.count = r_read_count.read() + 1; |
2100 | | } |
2101 | | else // Counter mode |
2102 | | { |
2103 | | entry.owner.srcid = 0; |
2104 | | entry.owner.inst = false; |
2105 | | entry.count = r_read_count.read() + 1; |
2106 | | } |
2107 | | } |
2108 | | else // Uncached read |
2109 | | { |
2110 | | entry.owner.srcid = r_read_copy.read(); |
2111 | | entry.owner.inst = r_read_copy_inst.read(); |
2112 | | entry.count = r_read_count.read(); |
2113 | | } |
2114 | | |
2115 | | #if DEBUG_MEMC_READ |
2116 | | if(m_debug) |
2117 | | std::cout << " <MEMC " << name() << " READ_DIR_HIT> Update directory entry:" |
2118 | | << " addr = " << std::hex << m_cmd_read_addr_fifo.read() |
2119 | | << " / set = " << std::dec << set |
2120 | | << " / way = " << way |
2121 | | << " / owner_id = " << std::hex << entry.owner.srcid |
2122 | | << " / owner_ins = " << std::dec << entry.owner.inst |
2123 | | << " / count = " << entry.count |
2124 | | << " / is_cnt = " << entry.is_cnt << std::endl; |
2125 | | #endif |
2126 | | m_cache_directory.write(set, way, entry); |
2127 | | r_read_fsm = READ_RSP; |
2128 | | break; |
2129 | | } |
2130 | | /////////////////// |
2131 | | case READ_HEAP_REQ: // Get the lock to the HEAP directory |
2132 | | { |
2133 | | if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
2134 | | { |
2135 | | r_read_fsm = READ_HEAP_LOCK; |
2136 | | } |
2137 | | |
2138 | | #if DEBUG_MEMC_READ |
2139 | | if(m_debug) |
2140 | | std::cout << " <MEMC " << name() << " READ_HEAP_REQ>" |
2141 | | << " Requesting HEAP lock " << std::endl; |
2142 | | #endif |
2143 | | break; |
2144 | | } |
2145 | | |
2146 | | //////////////////// |
2147 | | case READ_HEAP_LOCK: // read data in cache, update the directory |
2148 | | // and prepare the HEAP update |
2149 | | { |
2150 | | if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
2151 | | { |
2152 | | // enter counter mode when we reach the limit of copies or the heap is full |
2153 | | bool go_cnt = (r_read_count.read() >= m_max_copies) or m_heap.is_full(); |
2154 | | |
2155 | | // read data in the cache |
2156 | | size_t set = m_y[(addr_t)(m_cmd_read_addr_fifo.read())]; |
2157 | | size_t way = r_read_way.read(); |
2158 | | |
2159 | | m_cache_data.read_line(way, set, r_read_data); |
2160 | | |
2161 | | // update the cache directory |
2162 | | DirectoryEntry entry; |
2163 | | entry.valid = true; |
2164 | | entry.is_cnt = go_cnt; |
2165 | | entry.dirty = r_read_dirty.read(); |
2166 | | entry.tag = r_read_tag.read(); |
2167 | | entry.lock = r_read_lock.read(); |
2168 | | entry.count = r_read_count.read() + 1; |
2169 | | |
2170 | | if(not go_cnt) // Not entering counter mode |
2171 | | { |
2172 | | entry.owner.srcid = r_read_copy.read(); |
2173 | | entry.owner.inst = r_read_copy_inst.read(); |
2174 | | entry.ptr = m_heap.next_free_ptr(); // set pointer on the heap |
2175 | | } |
2176 | | else // Entering Counter mode |
2177 | | { |
2178 | | entry.owner.srcid = 0; |
2179 | | entry.owner.inst = false; |
2180 | | entry.ptr = 0; |
2181 | | } |
2182 | | |
2183 | | m_cache_directory.write(set, way, entry); |
2184 | | |
2185 | | // prepare the heap update (add an entry, or clear the linked list) |
2186 | | if(not go_cnt) // not switching to counter mode |
2187 | | { |
2188 | | // We test if the next free entry in the heap is the last |
2189 | | HeapEntry heap_entry = m_heap.next_free_entry(); |
2190 | | r_read_next_ptr = heap_entry.next; |
2191 | | r_read_last_free = (heap_entry.next == m_heap.next_free_ptr()); |
2192 | | |
2193 | | r_read_fsm = READ_HEAP_WRITE; // add an entry in the HEAP |
2194 | | } |
2195 | | else // switching to counter mode |
2196 | | { |
2197 | | if(r_read_count.read() >1) // heap must be cleared |
2198 | | { |
2199 | | HeapEntry next_entry = m_heap.read(r_read_ptr.read()); |
2200 | | r_read_next_ptr = m_heap.next_free_ptr(); |
2201 | | m_heap.write_free_ptr(r_read_ptr.read()); |
2202 | | |
2203 | | if(next_entry.next == r_read_ptr.read()) // last entry |
2204 | | { |
2205 | | r_read_fsm = READ_HEAP_LAST; // erase the entry |
2206 | | } |
2207 | | else // not the last entry |
2208 | | { |
2209 | | r_read_ptr = next_entry.next; |
2210 | | r_read_fsm = READ_HEAP_ERASE; // erase the list |
2211 | | } |
2212 | | } |
2213 | | else // the heap is not used / nothing to do |
2214 | | { |
2215 | | r_read_fsm = READ_RSP; |
2216 | | } |
2217 | | } |
2218 | | |
2219 | | #if DEBUG_MEMC_READ |
2220 | | if(m_debug) |
2221 | | std::cout << " <MEMC " << name() << " READ_HEAP_LOCK> Update directory:" |
2222 | | << " tag = " << std::hex << entry.tag |
2223 | | << " set = " << std::dec << set |
2224 | | << " way = " << way |
2225 | | << " count = " << entry.count |
2226 | | << " is_cnt = " << entry.is_cnt << std::endl; |
2227 | | #endif |
2228 | | } |
2229 | | else |
2230 | | { |
2231 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_LOCK" |
2232 | | << "Bad HEAP allocation" << std::endl; |
2233 | | exit(0); |
2234 | | } |
2235 | | break; |
2236 | | } |
2237 | | ///////////////////// |
2238 | | case READ_HEAP_WRITE: // add an entry in the heap |
2239 | | { |
2240 | | if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
2241 | | { |
2242 | | HeapEntry heap_entry; |
2243 | | heap_entry.owner.srcid = m_cmd_read_srcid_fifo.read(); |
2244 | | heap_entry.owner.inst = ((m_cmd_read_pktid_fifo.read() & 0x2) != 0); |
2245 | | |
2246 | | if(r_read_count.read() == 1) // creation of a new linked list |
2247 | | { |
2248 | | heap_entry.next = m_heap.next_free_ptr(); |
2249 | | } |
2250 | | else // head insertion in existing list |
2251 | | { |
2252 | | heap_entry.next = r_read_ptr.read(); |
2253 | | } |
2254 | | m_heap.write_free_entry(heap_entry); |
2255 | | m_heap.write_free_ptr(r_read_next_ptr.read()); |
2256 | | if(r_read_last_free.read()) m_heap.set_full(); |
2257 | | |
2258 | | r_read_fsm = READ_RSP; |
2259 | | |
2260 | | #if DEBUG_MEMC_READ |
2261 | | if(m_debug) |
2262 | | std::cout << " <MEMC " << name() << " READ_HEAP_WRITE> Add an entry in the heap:" |
2263 | | << " owner_id = " << std::hex << heap_entry.owner.srcid |
2264 | | << " owner_ins = " << std::dec << heap_entry.owner.inst << std::endl; |
2265 | | #endif |
2266 | | } |
2267 | | else |
2268 | | { |
2269 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_WRITE" |
2270 | | << "Bad HEAP allocation" << std::endl; |
2271 | | exit(0); |
2272 | | } |
2273 | | break; |
2274 | | } |
2275 | | ///////////////////// |
2276 | | case READ_HEAP_ERASE: |
2277 | | { |
2278 | | if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
2279 | | { |
2280 | | HeapEntry next_entry = m_heap.read(r_read_ptr.read()); |
2281 | | if(next_entry.next == r_read_ptr.read()) |
2282 | | { |
2283 | | r_read_fsm = READ_HEAP_LAST; |
2284 | | } |
2285 | | else |
2286 | | { |
2287 | | r_read_ptr = next_entry.next; |
2288 | | r_read_fsm = READ_HEAP_ERASE; |
2289 | | } |
2290 | | } |
2291 | | else |
2292 | | { |
2293 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_ERASE" |
2294 | | << "Bad HEAP allocation" << std::endl; |
2295 | | exit(0); |
2296 | | } |
2297 | | break; |
2298 | | } |
2299 | | |
2300 | | //////////////////// |
2301 | | case READ_HEAP_LAST: |
2302 | | { |
2303 | | if(r_alloc_heap_fsm.read() == ALLOC_HEAP_READ) |
2304 | | { |
2305 | | HeapEntry last_entry; |
2306 | | last_entry.owner.srcid = 0; |
2307 | | last_entry.owner.inst = false; |
2308 | | |
2309 | | if(m_heap.is_full()) |
2310 | | { |
2311 | | last_entry.next = r_read_ptr.read(); |
2312 | | m_heap.unset_full(); |
2313 | | } |
2314 | | else |
2315 | | { |
2316 | | last_entry.next = r_read_next_ptr.read(); |
2317 | | } |
2318 | | m_heap.write(r_read_ptr.read(),last_entry); |
2319 | | r_read_fsm = READ_RSP; |
2320 | | } |
2321 | | else |
2322 | | { |
2323 | | std::cout << "VCI_MEM_CACHE ERROR " << name() << " READ_HEAP_LAST" |
2324 | | << "Bad HEAP allocation" << std::endl; |
2325 | | exit(0); |
2326 | | } |
2327 | | break; |
2328 | | } |
2329 | | ////////////// |
2330 | | case READ_RSP: // request the TGT_RSP FSM to return data |
2331 | | { |
2332 | | if(!r_read_to_tgt_rsp_req) |
2333 | | { |
2334 | | for(size_t i=0 ; i<m_words ; i++) r_read_to_tgt_rsp_data[i] = r_read_data[i]; |
2335 | | r_read_to_tgt_rsp_word = m_x[(addr_t) m_cmd_read_addr_fifo.read()]; |
2336 | | r_read_to_tgt_rsp_length = m_cmd_read_length_fifo.read(); |
2337 | | r_read_to_tgt_rsp_srcid = m_cmd_read_srcid_fifo.read(); |
2338 | | r_read_to_tgt_rsp_trdid = m_cmd_read_trdid_fifo.read(); |
2339 | | r_read_to_tgt_rsp_pktid = m_cmd_read_pktid_fifo.read(); |
2340 | | r_read_to_tgt_rsp_ll_key = r_read_ll_key.read(); |
2341 | | cmd_read_fifo_get = true; |
2342 | | r_read_to_tgt_rsp_req = true; |
2343 | | r_read_fsm = READ_IDLE; |
2344 | | |
2345 | | #if DEBUG_MEMC_READ |
2346 | | if(m_debug) |
2347 | | std::cout << " <MEMC " << name() << " READ_RSP> Request TGT_RSP FSM to return data:" |
2348 | | << " rsrcid = " << std::hex << m_cmd_read_srcid_fifo.read() |
2349 | | << " / address = " << std::hex << m_cmd_read_addr_fifo.read() |
2350 | | << " / nwords = " << std::dec << m_cmd_read_length_fifo.read() << std::endl; |
2351 | | #endif |
2352 | | } |
2353 | | break; |
2354 | | } |
2355 | | /////////////////// |
2356 | | case READ_TRT_LOCK: // read miss : check the Transaction Table |
2357 | | { |
2358 | | if(r_alloc_trt_fsm.read() == ALLOC_TRT_READ) |
2359 | | { |
2360 | | size_t index = 0; |
2361 | | addr_t addr = (addr_t) m_cmd_read_addr_fifo.read(); |
2362 | | bool hit_read = m_trt.hit_read(m_nline[addr], index); |
2363 | | bool hit_write = m_trt.hit_write(m_nline[addr]); |
2364 | | bool wok = not m_trt.full(index); |
2365 | | |
2366 | | if(hit_read or !wok or hit_write) // line already requested or no space |
2367 | | { |
2368 | | if(!wok) m_cpt_trt_full++; |
2369 | | if(hit_read or hit_write) m_cpt_trt_rb++; |
2370 | | r_read_fsm = READ_IDLE; |
2371 | | } |
2372 | | else // missing line is requested to the XRAM |
2373 | | { |
2374 | | m_cpt_read_miss++; |
2375 | | r_read_trt_index = index; |
2376 | | r_read_fsm = READ_TRT_SET; |
2377 | | } |
2378 | | |
2379 | | #if DEBUG_MEMC_READ |
2380 | | if(m_debug) |
2381 | | std::cout << " <MEMC " << name() << " READ_TRT_LOCK> Check TRT:" |
2382 | | << " hit_read = " << hit_read |
2383 | | << " / hit_write = " << hit_write |
2384 | | << " / full = " << !wok << std::endl; |
2385 | | #endif |
2386 | | } |
2387 | | break; |
2388 | | } |
2389 | | ////////////////// |
2390 | | case READ_TRT_SET: // register get transaction in TRT |
2391 | | { |
2392 | | if(r_alloc_trt_fsm.read() == ALLOC_TRT_READ) |
2393 | | { |
2394 | | m_trt.set( r_read_trt_index.read(), |
2395 | | true, // GET |
2396 | | m_nline[(addr_t)(m_cmd_read_addr_fifo.read())], |
2397 | | m_cmd_read_srcid_fifo.read(), |
2398 | | m_cmd_read_trdid_fifo.read(), |
2399 | | m_cmd_read_pktid_fifo.read(), |
2400 | | true, // proc read |
2401 | | m_cmd_read_length_fifo.read(), |
2402 | | m_x[(addr_t)(m_cmd_read_addr_fifo.read())], |
2403 | | std::vector<be_t> (m_words,0), |
2404 | | std::vector<data_t> (m_words,0), |
2405 | | r_read_ll_key.read() ); |
2406 | | #if DEBUG_MEMC_READ |
2407 | | if(m_debug) |
2408 | | std::cout << " <MEMC " << name() << " READ_TRT_SET> Set a GET in TRT:" |
2409 | | << " address = " << std::hex << m_cmd_read_addr_fifo.read() |
2410 | | << " / srcid = " << std::hex << m_cmd_read_srcid_fifo.read() << std::endl; |
2411 | | #endif |
2412 | | r_read_fsm = READ_TRT_REQ; |
2413 | | } |
2414 | | break; |
2415 | | } |
2416 | | |
2417 | | ////////////////// |
2418 | | case READ_TRT_REQ: // consume the read request in FIFO and send it to IXR_CMD_FSM |
2419 | | { |
2420 | | if(not r_read_to_ixr_cmd_req) |
2421 | | { |
2422 | | cmd_read_fifo_get = true; |
2423 | | r_read_to_ixr_cmd_req = true; |
2424 | | r_read_to_ixr_cmd_index = r_read_trt_index.read(); |
2425 | | r_read_fsm = READ_IDLE; |
2426 | | |
2427 | | #if DEBUG_MEMC_READ |
2428 | | if(m_debug) |
2429 | | std::cout << " <MEMC " << name() << " READ_TRT_REQ> Request GET transaction for address " |
2430 | | << std::hex << m_cmd_read_addr_fifo.read() << std::endl; |
2431 | | #endif |
2432 | | } |
2433 | | break; |
2434 | | } |
2435 | | } // end switch read_fsm |
2436 | | |
2437 | | /////////////////////////////////////////////////////////////////////////////////// |
2438 | | // WRITE FSM |
2439 | | /////////////////////////////////////////////////////////////////////////////////// |
2440 | | // The WRITE FSM handles the write bursts and sc requests sent by the processors. |
2441 | | // All addresses in a burst must be in the same cache line. |
2442 | | // A complete write burst is consumed in the FIFO & copied to a local buffer. |
2443 | | // Then the FSM takes the lock protecting the cache directory, to check |
2444 | | // if the line is in the cache. |
2445 | | // |
2446 | | // - In case of HIT, the cache is updated. |
2447 | | // If there is no other copy, an acknowledge response is immediately |
2448 | | // returned to the writing processor. |
2449 | | // If the data is cached by other processors, a coherence transaction must |
2450 | | // be launched (sc requests always require a coherence transaction): |
2451 | | // It is a multicast update if the line is not in counter mode: the processor |
2452 | | // takes the lock protecting the Update Table (UPT) to register this transaction. |
2453 | | // If the UPT is full, it releases the lock(s) and retry. Then, it sends |
2454 | | // a multi-update request to all owners of the line (but the writer), |
2455 | | // through the CC_SEND FSM. In case of coherence transaction, the WRITE FSM |
2456 | | // does not respond to the writing processor, as this response will be sent by |
2457 | | // the MULTI_ACK FSM when all update responses have been received. |
2458 | | // It is a broadcast invalidate if the line is in counter mode: The line |
2459 | | // should be erased in memory cache, and written in XRAM with a PUT transaction, |
2460 | | // after registration in TRT. |
2461 | | // |
2462 | | // - In case of MISS, the WRITE FSM takes the lock protecting the transaction |
2463 | | // table (TRT). If a read transaction to the XRAM for this line already exists, |
2464 | | // it writes in the TRT (write buffer). Otherwise, if a TRT entry is free, |
2465 | | // the WRITE FSM register a new transaction in TRT, and sends a GET request |
2466 | | // to the XRAM. If the TRT is full, it releases the lock, and waits. |
2467 | | // Finally, the WRITE FSM returns an aknowledge response to the writing processor. |
2468 | | ///////////////////////////////////////////////////////////////////////////////////// |
2469 | | |
2470 | | //std::cout << std::endl << "write_fsm" << std::endl; |
2471 | | |
2472 | | switch(r_write_fsm.read()) |
2473 | | { |
2474 | | //////////////// |
2475 | | case WRITE_IDLE: // copy first word of a write burst in local buffer |
2476 | | { |
2477 | | if(m_cmd_write_addr_fifo.rok()) |
2478 | | { |
2479 | | if((m_cmd_write_pktid_fifo.read() & 0x7) == TYPE_SC) |
2480 | | { |
2481 | | m_cpt_sc++; |
2482 | | } |
2483 | | else |
2484 | | { |
2485 | | m_cpt_write++; |
2486 | | m_cpt_write_cells++; |
2487 | | } |
2488 | | |
2489 | | // consume a word in the FIFO & write it in the local buffer |
2490 | | cmd_write_fifo_get = true; |
2491 | | size_t index = m_x[(addr_t)(m_cmd_write_addr_fifo.read())]; |
2492 | | |
2493 | | r_write_address = (addr_t)(m_cmd_write_addr_fifo.read()); |
2494 | | r_write_word_index = index; |
2495 | | r_write_word_count = 1; |
2496 | | r_write_data[index] = m_cmd_write_data_fifo.read(); |
2497 | | r_write_srcid = m_cmd_write_srcid_fifo.read(); |
2498 | | r_write_trdid = m_cmd_write_trdid_fifo.read(); |
2499 | | r_write_pktid = m_cmd_write_pktid_fifo.read(); |
2500 | | r_write_pending_sc = false; |
2501 | | |
2502 | | // initialize the be field for all words |
2503 | | for(size_t word=0 ; word<m_words ; word++) |
2504 | | { |
2505 | | if(word == index) r_write_be[word] = m_cmd_write_be_fifo.read(); |
2506 | | else r_write_be[word] = 0x0; |
2507 | | } |
2508 | | |
2509 | | if (m_cmd_write_eop_fifo.read() or ((m_cmd_write_pktid_fifo.read() & 0x7) == TYPE_SC)) |
2510 | | { |
2511 | | r_write_fsm = WRITE_DIR_REQ; |
2512 | | } |
2513 | | else |
2514 | | { |
2515 | | r_write_fsm = WRITE_NEXT; |
2516 | | } |
| 2645 | //////////////// |
| 2646 | case WRITE_IDLE: // copy first word of a write burst in local buffer |
| 2647 | { |
| 2648 | if (m_cmd_write_addr_fifo.rok()) |
| 2649 | { |
| 2650 | // consume a word in the FIFO & write it in the local buffer |
| 2651 | cmd_write_fifo_get = true; |
| 2652 | size_t index = m_x[(addr_t)(m_cmd_write_addr_fifo.read())]; |
| 2653 | |
| 2654 | r_write_address = (addr_t)(m_cmd_write_addr_fifo.read()); |
| 2655 | r_write_word_index = index; |
| 2656 | r_write_word_count = 1; |
| 2657 | r_write_data[index] = m_cmd_write_data_fifo.read(); |
| 2658 | r_write_srcid = m_cmd_write_srcid_fifo.read(); |
| 2659 | r_write_trdid = m_cmd_write_trdid_fifo.read(); |
| 2660 | r_write_pktid = m_cmd_write_pktid_fifo.read(); |
| 2661 | r_write_pending_sc = false; |
| 2662 | |
| 2663 | // initialize the be field for all words |
| 2664 | for(size_t word=0 ; word<m_words ; word++) |
| 2665 | { |
| 2666 | if (word == index) r_write_be[word] = m_cmd_write_be_fifo.read(); |
| 2667 | else r_write_be[word] = 0x0; |
| 2668 | } |
| 2669 | |
| 2670 | if (m_cmd_write_eop_fifo.read() or ((m_cmd_write_pktid_fifo.read() & 0x7) == TYPE_SC)) |
| 2671 | { |
| 2672 | r_write_fsm = WRITE_DIR_REQ; |
| 2673 | } |
| 2674 | else |
| 2675 | { |
| 2676 | r_write_fsm = WRITE_NEXT; |
| 2677 | } |