Chủ Nhật, 14 tháng 7, 2019

[SystemC][TLM] Bài 3 - Tagged simple socket

Như tiêu đề, bài viết này trình bày về "Tagged simple socket" và ứng dụng, một biến thể của simple socket trình bày trong bài 1bài 2. Bài viết này cũng sẽ lấy lại ví dụ SCPU (Simple CPU) và áp dụng "tagged simple socket" cho model này nên các bạn cũng cần xem lại các bài viết mô tả về thiết kế này (bài 1, bài 2, bài 3, bài 4, bài 5bài 6).

1) Tagged simple socket
"Tagged simple socket" là một simple socket được gắn thêm "thẻ định danh", gọi là tag. Thẻ định danh này là một số nguyên (integer) và còn được gọi là id.
id được sử dụng trong trường hợp "dùng một callback cho nhiều initiator socket hoặc nhiều target socket". Trường hợp này, id sẽ giúp callback phân biệt từng socket.
Callback được sử dụng ở target socket để lấy thông tin và dữ liệu của transaction gửi từ initiator socket; Đồng thời, gửi đáp ứng (response) về trạng thái transaction cho initiator. Nếu không sử dụng socket có gắn id, mỗi method b_transport của một kết nối socket cần một callback riêng.
Hình 1: Callback trên simple socket
Hình 2: Callback trên tagged simple socket
Một id sẽ được gán ở đối số cuối cùng của method đăng ký callback. Một id là đối số đầu tiên của method callback. Ví dụ:
struct my_target: sc_module
{
  tlm_utils::simple_target_socket_tagged<my_target> socket1;
  tlm_utils::simple_target_socket_tagged<my_target> socket2;
  //
 SC_CTOR(my_target): socket1("socket1"), socket2("socket2")
  {
 socket1.register_b_transport(this, &my_target::b_transport, 1); // Registered with id = 1
 socket2.register_b_transport(this, &my_target::b_transport, 2); // Registered with id = 2
  }
  void b_transport(int id, Transaction& trans, sc_time& delay); // May be called with id = 1 or id = 2
  ...
};
Đoạn code trên khai báo 2 target socket loại tagged socket1 socket2. Callback cho b_transport chỉ có một và được sử dụng trên cả socket1 và socket2, đó là:
void b_transport(int id, Transaction& trans, sc_time& delay);
Việc đăng ký callback cho b_transport trên socket1 socket2 sẽ được phân biệt bởi id, đối số cuối cùng được khai báo ở method register_b_transport.
2) Áp dụng cho ví dụ SCPU
Trong ví dụ SCPU, khối DECODER nhận dữ liệu từ hai khối FETCH và EXECUTE. Dữ liệu ở đây là giá trị các tín hiệu điều khiển được đóng gói thành một transaction có kiểu tlm_generic_payload (xem lại bài 1). DECODER có hai target socket là fetch2dc_socket và ex2dc_socket để nhận transaction từ FETCH và EXECUTE thông qua initiator socket tương ứng. Hai target socket đều là loại simple socket và có method callback riêng là fetch2dc_transport và ex2dc_transport.
Hình 3: Callback riêng trên mỗi target socket loại simple socket
Đăng ký callback cho target socket của DECODER trong constructor (SC_CTOR) của file scpu_decoder.h như sau:
fetch2dc_socket.register_b_transport(this, &scpu_decoder::fetch2dc_transport);
ex2dc_socket.register_b_transport(this, &scpu_decoder::ex2dc_transport);
Chú ý, phần tô xanh của đoạn code trên là tên method callback trên mỗi target socket. Code SystemC cho method callback fetch2dc_transport như sau:
virtual void fetch2dc_transport (tlm::tlm_generic_payload& fetch2dc_trans, sc_time &delay) {
 tlm::tlm_command dc_cmd = fetch2dc_trans.get_command();
    unsigned char*   dc_ptr = fetch2dc_trans.get_data_ptr();
     unsigned int     dc_len = fetch2dc_trans.get_data_length();
     unsigned char* dc_byt = fetch2dc_trans.get_byte_enable_ptr();
     unsigned int    dc_wid = fetch2dc_trans.get_streaming_width();
     //
     if (dc_cmd != tlm::TLM_WRITE_COMMAND)
       SC_REPORT_ERROR("TLM-2", "Target only support TLM_WRITE_COMMAND for the transaction from FETCH to DECODER");
memcpy (&fetch2dc_pkt_tmp, dc_ptr, dc_len);    fetch2dc_pkt = fetch2dc_pkt_tmp;    
fetch_ir   = fetch2dc_pkt.range(23,16); 
fetch_dr   = fetch2dc_pkt.range(15,8);      
fetch_mem_dout  = fetch2dc_pkt.range(7,0);   
// Set response status to indicate successful completion
    fetch2dc_trans.set_response_status( tlm::TLM_OK_RESPONSE );
   }
Code SystemC cho method callback ex2dc_transport như sau:
virtual void ex2dc_transport (tlm::tlm_generic_payload& ex2dc_trans, sc_time &delay) {
     tlm::tlm_command dc_cmd = ex2dc_trans.get_command();
     unsigned char*   dc_ptr = ex2dc_trans.get_data_ptr();
     unsigned int     dc_len = ex2dc_trans.get_data_length();
     unsigned char*   dc_byt = ex2dc_trans.get_byte_enable_ptr();
     unsigned int     dc_wid = ex2dc_trans.get_streaming_width();
     if (dc_cmd != tlm::TLM_WRITE_COMMAND)
       SC_REPORT_ERROR("TLM-2", "Target only support TLM_WRITE_COMMAND for the transaction from EXECUTE to DECODER");
memcpy (&ex2dc_pkt_tmp, dc_ptr, dc_len);  
ex2dc_pkt = ex2dc_pkt_tmp; 
ex_dout   = ex2dc_pkt.range(8,0);  
// Set response status to indicate successful completion
     ex2dc_trans.set_response_status( tlm::TLM_OK_RESPONSE );
   }
Các bạn có thể nhận thấy đoạn code của method callback fetch2dc_transport và ex2dc_transport chỉ khác nhau phần được tô màu xanh. Đây là phần code phân tách gói dữ liệu của transaction gửi từ FETCH và EXECUTE.
Trong trường hợp này, chúng ta có thể thay thế simple socket thành tagged simple socket. Trong đó:
  • fetch2dc_socket được gán id = 1
  • ex2dc_socket được gán id = 2
Một method callback duy nhất được sử dụng, tên là common_transport, sẽ dựa trên id để biết transaction được lấy từ target socket nào, của FETCH hat EXECUTE. Từ đó, phần code phân tách gói dữ liệu tương ứng sẽ được thực thi.
Hình 4: Sử dụng tagged simple socket cho khối DECODER
Trong file scpu_decoder.h, những phần code liên quan đến việc khai báo target socket và callback sẽ được thay đổi như sau:
  • Khai báo tagged simple socket:
tlm_utils::simple_target_socket_tagged<scpu_decoder> fetch2dc_socket;
tlm_utils::simple_target_socket_tagged<scpu_decoder> ex2dc_socket;
  • Đăng ký callback trong constructor (SC_CTOR) với cùng một method callback là common_transport nhưng với 2 id khác nhau.
fetch2dc_socket.register_b_transport(this, &scpu_decoder::common_transport, 1);
         ex2dc_socket.register_b_transport(this, &scpu_decoder::common_transport, 2);
  • Method callback xử lý chung cho trên cả 2 target socket:
virtual void common_transport (int id, tlm::tlm_generic_payload& common_trans, sc_time &delay) {     tlm::tlm_command dc_cmd = common_trans.get_command();
     unsigned char*   dc_ptr = common_trans.get_data_ptr();
     unsigned int     dc_len = common_trans.get_data_length();
     unsigned char*   dc_byt = common_trans.get_byte_enable_ptr();
     unsigned int     dc_wid = common_trans.get_streaming_width();
     if (dc_cmd != tlm::TLM_WRITE_COMMAND)
       SC_REPORT_ERROR("TLM-2", "Target only support TLM_WRITE_COMMAND for the transaction from FETCH to DECODER");
     //
     if (id == 1) { //Get data from FETCH 
       memcpy (&fetch2dc_pkt_tmp, dc_ptr, dc_len);
       fetch2dc_pkt = fetch2dc_pkt_tmp;
       //
       fetch_ir   = fetch2dc_pkt.range(23,16);
       fetch_dr   = fetch2dc_pkt.range(15,8);
       fetch_mem_dout  = fetch2dc_pkt.range(7,0);
     }
     else { //Get data from EXECUTE when id=2  
       memcpy (&ex2dc_pkt_tmp, dc_ptr, dc_len);
       ex2dc_pkt = ex2dc_pkt_tmp;
       //
       ex_dout   = ex2dc_pkt.range(8,0);
     }
     // Set response status to indicate successful completion
     common_trans.set_response_status( tlm::TLM_OK_RESPONSE );
   }
Code hoàn chỉnh của ví dụ SCPU sử dụng tagged simple socket có thể được tải dưới bài viết này.

Dữ liệu có thể download:
pass (nếu có): vlsi_technology

Tham khảo:
1) IEEE Computer Society; IEEE Standard for Standard SystemC® Language Reference Manual - IEEE Std 1666™-20119 January 2012

Lịch sử cập nhật:
1) 2019.July.14 - Tạo lần đầu

1. Trương Công Hoàng Việt
2. Lê Hoàng Vân
3. Nguyễn Hùng Quân

0 bình luận:

Đăng nhận xét