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

[SystemC][TLM] Bài 4 - Multi-sockets

Bài viết này trình bày về cách sử dụng và kết nối multi-socket trong TLM-2.0. Ví dụ được sử dụng trong bài viết là SPCU, lấy từ các bài viết trước (bài 1, bài 2, bài 3, bài 4, bài 5bài 6) về SystemC nên các bạn cần đọc các bài viết trước để hiểu chi tiết hơn. Về các loại socket khác, các bạn tham khảo các bài viết bài 1bài 2 và bài 3.

1) Tổng quan về multi-socket
Trong một model thực tế, một khối (block) có thể gửi dữ liệu của nó cho nhiều khối khác hoặc nhận dữ liệu từ nhiều khối khác nhau. Trong các bài trước (bài 1bài 2 và bài 3), chúng ta sử dụng kết nối điểm-điểm thông qua các simple socket để thực hiện việc truyền và nhận các gói dữ liệu. Gói dữ liệu ở đây là các transaction được gửi qua hàm b_transport.
Hình 1: Kết nối điểm-điểm sử dụng simple socket
Trong hình minh họa trên đây, một khối muốn truyền dữ liệu cho khối khác thì một cặp initiator socket và target socket được tạo ra để kết nối giữa khối truyền và khối nhận. Với dạng kết nối điểm-điểm, một khối như DECODER cần nhiều initiator socket và target socket để truyền/nhận dữ liệu từ/đến nhiều khối khác nhau.
Để giảm số lượng kết nối này, chúng ta sử dụng kết nối multi-socket bao gồm:
  • multi_passthrough_initiator_socket cho initiator
  • multi_passthrough_target_socket cho target
Hai loại socket trên là biến thể của tagged simple socket, một loại socket được sử dụng để giảm số lượng callback thông qua việc định danh socket bằng một số nguyên gọi là id hoặc tag.
Sử dụng multi_passthrough_initiator_socket giúp một initiator socket có thể được kết nối (bind) đến nhiều target socket.
Sử dụng multi_passthrough_target_socket giúp một target socket có thể được kết nối (bind) đến nhiều initiator socket.
Hình 2: Kết nối multi-socket sử dụng multi_passthrough_*_socket
Bên cạnh đó, chúng còn hỗ trợ kết nối theo thứ bậc (hierarchy). Trong khi các loại socket khác chỉ hỗ trợ kết nối (bind) giữa một initiator socket và một target socket thì multi_passthrough_initiator_socket và multi_passthrough_target_socket hỗ trợ kết nối (bind) dùng loại theo hierarchy. Nghĩa là, initiator socket của một instance con có thể được kết nối đến initiator socket của khối cha (child-to-parent). Target socket của một instance con có thể được kết nối đến Target socket của khối cha. Xem hình minh họa dưới đây.
Hình 3: Kết nối socket theo hierarchy sử dụng multi_passthrough_*_socket
Đoạn code sau đây là một ví dụ trong tài liệu IEEE_1666-2011 cho kết nối từ một instance (child) đến khối cha (parent).
  • Khai báo một initiator socket loại multi_passthrough_initiator_socket tại khối con
// Initiator component with a multi-socketstruct Initiator: sc_module{
  tlm_utils::multi_passthrough_initiator_socket<Initiator> socket; 
SC_CTOR(Initiator) : socket("socket") {  ...};
  • Tạo instance trong khối cha, khai báo một multi_passthrough_initiator_socket tại khối cha và kết nối (bind) socket của instance đến khối cha.
struct Initiator_parent: sc_module{ 
 tlm_utils::multi_passthrough_initiator_socket<Initiator_parent> socket; 
Initiator *initiator; 
SC_CTOR(Initiator_parent) : socket("socket") {    initiator = new Initiator("initiator");  
// Hierarchical binding of initiator socket on child to initiator socket on parent 
    initiator->socket.bind( socket );  
} 
};  
2) Ví dụ về multi-socket
Quay lại ví dụ SCPU, kết nối của khối DECODER sẽ được chuyển thành dạng multi-socket như hình minh họa sau đây.
Hình 4: Kết nối dạng multi-socket của DECODER
Như vậy, DECODER chỉ dùng một initiator socket là dc_output_socket và một target socket là dc_input_socket. Các điều chỉnh về SystemC code như sau:
  • Include header file mới trong scpu_decoder.h để sử dụng multi_pasthrough_*_socket
 #include "tlm_utils/multi_passthrough_initiator_socket.h"
 #include "tlm_utils/multi_passthrough_target_socket.h"
  • Khai báo lại initiator socket cho DECODER
tlm_utils::multi_passthrough_initiator_socket<scpu_decoder> dc_output_socket;
  • Khai báo lại target socket cho DECODER
tlm_utils::multi_passthrough_target_socket<scpu_decoder> dc_input_socket;
  • Đăng ký callback cho target socket
dc_input_socket.register_b_transport(this, &scpu_decoder::common_transport);
  • Viết hàm xử lý callback. Chú ý, để phân biệt gói dữ liệu (transaction) gửi đến target socket là từ FETCH hay EXECUTE. Nhóm tác giả sử dụng thêm trường address của tlm_generic_payload, nếu address=1 thì transaction đến từ FETCH, nếu address=2 thì transaction đến từ EXECUTE. Chú ý, các phần tô màu xanh là các điểm cần lưu ý của callback này.
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();
     unsigned int     dc_addr= common_trans.get_address();
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 (dc_addr == 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 dc_addr=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 );
   }
  • Thêm trường address cho transaction fetch2dc_trans trong file scpu_fetch.cpp ở khối FETCH và transaction ex2dc_trans trong file scpu_execute.cpp ở khối EXECUTE
fetch2dc_trans->set_address( 1 ); //Cho khối FETCH
ex2dc_trans->set_address( 2 ); //Cho khối EXECUTE
  • Kết nối các socket ở file scpu_top.cpp
 scpu_decoder_inst.dc_output_socket.bind(scpu_fetch_inst.dc2fetch_socket);        scpu_decoder_inst.dc_output_socket.bind(scpu_execute_inst.dc2ex_socket);       scpu_execute_inst.ex2dc_socket.bind(scpu_decoder_inst.dc_input_socket);       scpu_fetch_inst.fetch2dc_socket.bind(scpu_decoder_inst.dc_input_socket);
Code hoàn chỉnh có thể được tải phía 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™-2011; 9 January 2012

Lịch sử cập nhật:
1) 2019.July.21 - 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