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

[SystemC][TLM] Bài 2 - Mảng socket

Bài viết này trình bày cách khai báo và kết nối một mảng socket. Trước khi đọc bài viết này các bạn cần tham khảo các bài viết về SystemCTLM trước đó để biết các khái niệm và ví dụ SCPU được trình bày trong bài viết này.

1) Kết nối sử dụng simple socket
Trong bài 1, nhóm tác giả đã trình bày về việc chuyển kết nối giữa các module từ dạng tín hiệu (signal) thành các kết nối TLM thông qua các socket. Trong ví dụ SCPU, nhóm tác giả đã thực hiện việc chuyển đổi này dựa trên ý tưởng chính như sau:
  1. Tập hợp các tín hiệu (signal) ngõ ra (output) của một module thành một gói dữ liệu tlm_generic_payload
  2. Gửi gói dữ liệu đã đóng gói qua một initiator socket đến một target socket bằng hàm b_transport
  3. Target socket đại diện cho các ngõ vào (input) của một module. Tại target socket, gói dữ liệu được tách ra thành các bit chức năng mong muốn và đưa đến các process.
  4. Thời gian truyền một gói dữ liệu qua socket phải trong một chu kỳ xung clock để đảm bảo các khối hoạt động đúng trong từng chu kỳ.
Các bạn hãy tải code của bài 1 để tìm hiểu trước khi tiếp tục đọc bài viết này để so sánh sự khác nhau giữa cách làm trong bài viết này và cách làm thực hiện ở bài 1.

Hình 1: Kết nối socket trong ví dụ SCPU
Hình trên mô tả lại các kết nối socket của SCPU trong bài 1. Các bạn hãy chú ý đến initiator socket của khối DECODER. Sau khi đóng gọi tất cả output của khối này, gói dữ liệu được truyền qua dc2fetch_socket để đến khối FETCH và qua dc2ex_socket để đến khối EXECUTE.
Chúng ta nhận thấy cấu trúc hàm truyền dữ liệu qua socket của scpu_decoder::DC2FETCH_SOCKET() và scpu_decoder::DC2EX_SOCKET() trong file scpu_decoder.cpp là như nhau. Hai hàm này chỉ khác nhau tên socket. Trong trường hợp này, thay vì khai báo nhiều socket khác nhau, chúng ta có thể sử dụng mảng socket. Mảng socket giúp giảm đáng kể lượng code khai báo và kết nối socket. Đồng thời, việc quản lý các socket cũng dễ dàng hơn trong trường hợp một module tạo ra output đến nhiều module khác nhau.
2) Tạo và kết nối mảng socket
Để thực hiện, chúng ta sẽ thay thế hai initiator socket của DECODER bằng một mảng socket 2 phần tử. Mỗi phần tử tương đương với một initiator socket độc lập nối đến target socket của FETCH và EXECUTE.
Hình 2: Thay thế 2 initiator socket độc lập bằng 1 mảng socket tên dc_output_socket
Trong file scpu_decoder.h, chúng ta sẽ thay đổi code như hình sau:
Hình 3: Code của scpu_decoder.h
Trong file scpu_decoder.cpp, chúng ta sẽ thay 2 method DC2FETCH_SOCKET và DC2EX_SOCKET bằng một method duy nhất. Một vòng lặp được sử dụng để đảm bảo gói dữ liệu của DECODER được gửi qua cả hai phần tử socket trong mảng. Bên cạnh đó, sau mỗi lần gửi, trạng thái của gói dữ liệu cũng được kiểm tra bằng hàm is_response_error() và in ra thông điệp lỗi nếu có.
Hình 4: System C của file scpu_decoder.cpp
Cuối cùng, mô tả kết nối socket trong scpu_top.cpp được thay đổi cho phù hợp với cách khai báo socket mảng.
Hình 5: Kết nối socket trong file scpu_top.cpp
3) Khai báo mảng socket dạng con trỏ
Ngoài cách khai báo "đối tượng mảng socket", các bạn cũng có thể khai báo mảng "con trỏ socket". Khi khai báo dạng này một số code sẽ được điều chỉnh như sau:
File scpu_decoder.h, khai báo socket sử dụng thêm "*".
tlm_utils::simple_initiator_socket<scpu_decoder>* dc_output_socket[2];
Bên cạnh đó, trong constructor SC_CTOR(scpu_decoder), code cấp phát bộ nhớ cho socket được điều khiển (handle) bởi mảng con trỏ được thêm vào:
for (unsigned int i = 0; i < 2; i++) {
  char socket_name[20];
  sprintf(socket_name, "dc_output_socket_%d", i);
 dc_output_socket[i] = new tlm_utils::simple_initiator_socket<scpu_decoder>(socket_name);
        }
Nếu thiếu đoạn code trên, lỗi sẽ sinh ra trong phá trình chạy model. Đối với trường hợp này, bạn có thể nhận được thông điệp lỗi "Segmentation fault (core dumped)" khi thực thi file test_top.exe.
File scpu_decoder.cpp, code gọi hàm b_transport trong method scpu_decoder::DC_OUTPUT_SOCKET() sẽ đổi thành:
(*dc_output_socket[i])->b_transport( *dc_output_trans, wire_delay );  // Blocking transport call
File scpu_top.cpp, code kết nối socket được đổi thành:
scpu_decoder_inst.dc_output_socket[0]->bind(scpu_fetch_inst.dc2fetch_socket);
   scpu_decoder_inst.dc_output_socket[1]->bind(scpu_execute_inst.dc2ex_socket);
Như vậy, qua bài viết này, các bạn có thể hiểu cách khai báo và sử dụng một mảng socket. Mọi ý kiến đóng góp và trao đổi xin comment dưới bài viết.

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

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