Bạn đang muốn bắt tay vào thiết kế một lõi IP (IP core) nhưng không biết bắt đầu từ đâu? Bài viết này là một phần trong chuỗi bài viết hướng dẫn bạn đi từng bước để có thể thiết kế được một lõi IP hoàn chỉnh. Phương pháp được sử dụng ở đây là top-down, phân tích từ tổng quan đến chi tiết. Ví dụ được trình bày là một thiết kế CPU cơ bản (simple CPU).
Trong bài 1 và bài 2, chúng ta đã hiểu đến bước phân tích chi tiết từ khối trong một thiết kế vi mạch. Bài này sẽ thực hiện lý thuyết đã trình bày trong bài 2 trên ví dụ CPU 8 bit đơn giản tên SCPU.
1. Tổng quan
Ở hai bài trước, chúng ta đã thực hiện qua các bước sau:
- Nghiên cứu và tìm hiểu
- Phân tích tổng quan
- Phân tích chi tiết
- Tìm các tín hiệu giao tiếp giữa các khối chức năng
Trong bài này, chúng ta tiếp tục thực hiện bước 2 của "phân tích chi tiết" là "phân tích cấu trúc" cho từng khối chức năng. Việc phân tích cấu trúc thực chất là tìm sự phụ thuộc của ngõ ra (output) theo các ngõ vào (input). "Sự phụ thuộc" này có thể được thể hiện bằng 1 trong các cách như đã trình bày ở bài 2 nhưng trong bài này chỉ sử dụng mạch nguyên lý mức cổng logic để thể hiện.
Để phân tích một ngõ ra, một số vấn đề cần được quan tâm:
- Tín hiệu ngõ là từ mạch tổ hợp hay tuần tự?
- Nếu là mạch tuần tự thì có cần reset không?
- Nếu có reset thì loại reset là đồng bộ hay bất đồng bộ?
- Giá trị reset là bao nhiêu?
- Nếu là mạch tổ hợp thì chỉ cần chuyển xuống câu hỏi 2 và 3
- Tín hiệu ngõ ra có thể mang những giá trị nào?
- Tín hiệu nào quyết định giá trị của ngõ ra?
Xét lại ví dụ về CPU 8 bit SCPU, hiện tại chúng ta có được các thông tin quan trọng sau đây.
Hình 1. Hoạt động của các lệnh SCPU |
Hình 2. Sơ đồ khối SCPU |
|
Như đã trình bày, việc phất tích chi tiết cấu trúc một khối chức năng là tìm mạch nguyên lý cho từng ngõ ra theo các ngõ vào.
Khối FETCH có 2 tín hiệu ngõ ra, fetch_ir[7:0] và fetch_dr[7:0], nên chỉ cần tìm mạch nguyên lý cho 2 tin hiệu này là kết thúc bước phân tích cấu trúc của khối FETCH.
2.1 Phân tích tín hiệu fetch_ir[7:0]
Tín hiệu này cung cấp giá trị mã lệnh cho khối DECODER. Nó được lấy từ một thanh ghi và là mạch tuần tự. Giá trị của tín hiệu giải mã các tín hiệu điều khiển nên cần reset. Giá trị reset của thanh ghi sẽ là mã lệnh NOP, b0111_0000. Trong thiết kế này, tín hiệu reset rst_n sẽ tích cực mức thấp và là reset đồng bộ. Tín hiệu chỉ lấy giá trị từ ngõ ra MEMORY. Tín hiệu dc_load_ir sẽ quyết định khi nào nó được cập nhật giá trị mới.
Hình 4. Mạch nguyên lý tín hiệu fetch_ir[7:0] |
Ở đây, dc_load_ir là ngõ vào khối FETCH nên không cần phân tích thêm. Tín hiệu mem_dout[7:0] là ngõ ra của bộ nhớ MEMORY. Do bộ nhớ này không có sẵn nên phần này cũng phân tích luôn mô hình bộ nhớ này để sử dụng. Hoạt động của bộ nhớ các bạn xem lại bài 1. Mô hình cấu trúc chi tiết của bộ nhớ như sau:
Khối MEMORY đơn giản gồm 3 phần:
Hình 5. Cấu trúc chi tiết của khối bộ nhớ MEMORY |
- write_decoder: giải mã tín hiệu ghi vào mảng ô nhớ
- mem_array: mảng ô nhớ gồm 256 ô, mỗi ô 8 bit
- read_encoder: lựa chọn giá trị đọc từ mảng ô nhớ bằng địa chỉ truy xuất
Trong đó:
- Tín hiệu cho phép ghi mem_wr là dc_mem_wr, ngõ vào khối FETCH nên không cần phân tích thêm
- Bus dữ liệu ghi vào MEMORYlà dc_rd[7:0] vì MEMORY chỉ được ghi bằng giá trị Rd trong lệnh SWR và SWI, ngõ vào khối FETCH nên không cần phân tích thêm
Địa chỉ truy xuất MEMORY mem_addr[7:0] có thể mang các giá trị sau:
- Giá trị PC để truy xuất mã lệnh của chương trình
- Giá trị thanh ghi DR đối với lệnh đọc bộ nhớ LWI và ghi bộ nhớ SWI sử dụng địa chỉ là IMM
- Giá trị thanh ghi Rs đối với lệnh đọc bộ nhớ LWR và ghi bộ nhớ SWR sử dụng địa chỉ là giá trị thanh ghi Rs
Tín hiệu để lựa chọn giá trị địa chỉ của MEMORY là dc_addr_sel[1:0].
Hình 6. Mạch nguyên lý tạo địa chỉ truy xuất MEMORY |
Trong mạch tạo tín hiệu mem_addr[7:0], pc[7:0] và fetch_dr[7:0] không phải là ngõ vào khối FETCH.
pc[7:0] là một thanh ghi có giá trị reset ban đầu là 0 để chỉ đến ô nhớ bắt đầu chương trình. pc[7:0] được cập nhật giá trị mới khi dc_load_pc tích cực và giá trị cập nhật là giá trị IMM chứa trong thanh ghi DR hoặc giá trị sau khi tăng 1 đơn vị.
Hình 7. Mạch nguyên lý thanh ghi pc[7:0] |
fetch_dr[7:0] là thành ghi DR dùng để lưu giá trị IMM được đọc từ bộ nhớ trong các lệnh có IMM. Thanh ghi này cập nhật giá trị mới khi dc_load_dr tích cực và không cần reset vì đây là thanh ghi không dùng để tạo tín hiệu điều khiển.
Hình 8. Thanh ghi DR |
2.2 Phân tích tín hiệu fetch_mem_dout[7:0]
Tín hiệu này chính là ngõ ra của bộ nhớ mem_dout[7:0].
Hình 9. Tín hiệu fetch_mem_dout[7:0] |
Quá trình phân tích cấu trúc khối FETCH kết thúc vì tất cả các ngõ ra đã được xác định theo các ngõ vào
3. Phân tích chi tiết khối DECODER
Tương tự với khối DECODER, từng ngõ ra sẽ được phân tích chi tiết. Bạn có thể chọn một ngõ ra bất kỳ để thực hiện. Ở đây, các ngõ ra sẽ được chọn theo thứ tự từ trên xuống như hình sơ đồ tín hiệu đã minh họa.
3.1 Phân tích tín hiệu dc_load_pc
Theo bảng phân tích hoạt động của các lệnh thì PC được cập nhật ở chu kỳ 1 và chu kỳ 3 của một lệnh. Để xác định các chu kỳ hoạt động, một bộ đếm chu kỳ sẽ được sử dụng, gọi là ctrl_counter[1:0]. Chu kỳ 1 tương ứng với bộ đếm bằng 0, chu kỳ 2 bộ đếm bằng 1 và chu kỳ 3 bộ đếm bằng 2.
Thời điểm xóa bộ đếm về 0 phụ thuộc vào lệnh đó là lệnh nào, lệnh NOP là lệnh 1 chu kỳ, nhóm lệnh không có IMM là 2 chu kỳ và nhóm lệnh có IMM là 3 chu kỳ.
Hình 10. Bộ đếm số chu kỳ hoạt động của lệnh ctrl_counter[1:0] |
dc_load_pc sẽ tích cực khi bộ đến bằng 0 hoặc bằng 2, tức là khác 1.
Hình 11. Tín hiệu dc_load_pc |
3.2 Phân tích tín hiệu dc_imm
Tín hiệu này được sử dụng để chọn giá trị mà PC sẽ được cập nhật. Đối với các lệnh nhảy, ở chu kỳ thứ 3, PC có thể được nạp giá trị bằng giá trị IMM chứa trong thanh ghi DR. Như vậy, tín hiệu này sẽ hoạt động ở chu kỳ thứ 3 và tùy vào điều kiện của từng lệnh nhảy để tích cực phù hợp.
Hình 12. Mạch nguyên lý tín hiệu dc_imm |
3.3 Phân tích tín hiệu dc_addr_sel[1:0]
Đây là tín hiệu chọn địa chỉ cho MEMORY khối FETCH. Đối với lệnh LWR và SWR, ở chu kỳ 2, địa chỉ của MEMORY sẽ là giá trị thanh ghi Rs. Đối với lệnh LWI và SWI, ở chu kỳ 3, thì địa chỉ của MEMORY sẽ là giá trị thanh ghi DR. Tận dụng giá trị ctrl_counter[1:0] để thực hiện mạch cho tín hiệu dc_addr_sel[1:0]. Trường hợp còn lại, địa chỉ MEMORY luôn là PC.
Hình 13. Mạch nguyên lý tín hiệu dc_addr_sel[1:0] |
3.4 Phân tích tín hiệu dc_rs[7:0] và dc_rd[7:0]
Đây là hai tín hiệu được lựa chọn từ 4 thanh ghi R0, R1, R2 và R3 dựa trên giá trị trường Rs và Rd của mã lệnh.
Hình 14. Mạch nguyên lý của tín hiệu dc_rs[7:0] và dc_rd[7:0] |
Trong đó, các thanh ghi R0, R1, R2 và R3 có mạch nguyên lý như sau:
3.5 Phân tích tín hiệu dc_mem_wr
Hình 15. Mạch nguyên lý của các thanh ghi R0, R1, R2 và R3 |
Đây là tín hiệu cho phép ghi vào MEMORY ở khối FETCH. Tín hiệu chỉ tích cực ở lệnh SWR, chu kỳ 2 và lệnh SWI, chu kỳ 3.
Hình 16. Tín hiệu dc_mem_wr |
3.6 Phân tích tín hiệu dc_load_dr
Đây là tín hiệu cho phép nạp thanh ghi DR, xảy ra ở chu kỳ 2 của các lệnh có IMM.
Hình 17. Mạch nguyên lý tín hiệu dc_load_dr |
3.7 Phân tích tín hiệu dc_load_ir
Tín hiệu này chỉ tích cực ở chu kỳ thứ nhất để nạp thanh ghi IR.
Hình 18. TÍn hiệu dc_load_ir |
3.8 Phân tích tín hiệu dc_op[1:0]
Với chức năng lựa chọn toán tử thực thi ở khối EXECUTE. Dựa vào bảng mã lệnh, toán tử chỉ có 4 loại là AND, OR, ADD và SUB. Hai bit thấp của opcode sẽ được sử dụng để tạo tín hiệu này.
Hình 19. Tín hiệu lựa chọn toán tử cho khối EXECUTE |
4. Phân tích chi tiết khối EXECUTE
Khối EXCUTE chỉ chứa một ALU thực hiện bốn phép tính AND, OR, ADD và SUB. Khối này chỉ có một tín hiệu ngõ ra là kết quả của các phép tính trên.
HÌnh 20. Mạch nguyên lý tín hiệu ex_out[7:0] |
Việc phân tích cấu trúc chi tiết từng khối của CPU 8 bit SCPU đã hoàn thành. Bước tiếp theo là dựa trên các mạch nguyên lý để mô tả RTL code. Phần này sẽ được trình bày cụ thể trong bài tiếp theo
**Mọi ý kiến trao đổi và góp ý xin comment dưới bài viết.
0 bình luận:
Đăng nhận xét