Viết lên bản dựng CPU homebrew của tôi
Tin tức chung·Hacker News·1 lượt xem

Viết lên bản dựng CPU homebrew của tôi

Write up of my homebrew CPU build

AI Summary

Tác giả chia sẻ hành trình "tự làm" chiếc CPU 8-bit của riêng mình (WCPU-1), từ khâu mô phỏng đến khi biến nó thành phần cứng thực tế. Quá trình này đầy thử thách và "hạ thấp cái tôi", với những vấn đề dở khóc dở cười như đèn LED ngược hay các đường address "lơ lửng" không kết nối đúng. Dự án thực tế này không chỉ là một bản prototype để kiểm chứng thiết kế và cách đi dây, mà còn là minh chứng rõ nét cho đường cong học hỏi và những khó khăn bất ngờ khi chuyển logic số vào thế giới vật lý. Các developer đang có ý định tự xây dựng phần cứng custom, hãy chuẩn bị tinh thần cho việc debug mệt mỏi. Một lời khuyên hữu ích là nên cân nhắc sử dụng linh kiện DIP song song với SMT để việc thử nghiệm trên breadboard được dễ dàng hơn. Dù đã mô phỏng thành công, quá trình build thực tế vẫn sẽ là một chặng đường học tập đáng kể và không ít bất ngờ.

Xin chào! Đây là phần thứ ba của loạt bài về WCPU-1, máy tính 8-bit homebrew của tôi. Hãy xem Phần 1 và Phần 2!Tóm tắt/Giới thiệu #Hãy giải quyết vấn đề này bằng cách:Đừng nhìn thẳng vào mắt nó!Vì vậy, trong Phần 2 tôi...

Xin chào! Đây là phần thứ ba của loạt bài về WCPU-1, máy tính 8 bit homebrew của tôi.

Hãy xem Phần 1Phần 2!

Tóm tắt/Giới thiệu #

Hãy cùng giải quyết vấn đề này với:

<img src="https://willwarren.com/2026/03/12/building-my-own-cpu-part-3-from-simulation-to-hardware/cover.jpeg" alt="Ảnh chụp toàn bộ tòa nhà trong phòng tối. Tổ dây điện của một con chuột bao phủ một ánh sáng đỏ độc ác khi máy tính hoạt động" style=" max-width: 100%;">
Đừng nhìn thẳng vào mắt nó!

Vì vậy, trong Phần 2, tôi đã mô phỏng toàn bộ thiết kế trong Logisim-Evolution và tinh chỉnh nó cho đến khi tôi hài lòng. Tôi đã được khuyến khích, và cảm thấy khá tự tin rằng tôi sẽ không phạm phải bất kỳ sai lầm lớn nào với phần cứng thực sự…

“The ‘is this a pigeon’ meme but it says foreshadowing instead of pigeon”
Có lẽ...

Bài đăng này bao gồm những gì thực sự đã xảy ra khi tôi bắt đầu xây dựng vật lý. Spoiler: thật là khiêm tốn. Có đèn LED ngược, dòng địa chỉ nổi, EEPROM bị nguyền rủa và tại một thời điểm, tôi vừa học cách đọc nhị phân bằng cách nhìn chằm chằm vào một số đèn nhấp nháy vì tôi đã quá lười biếng hoặc mất tập trung để xây dựng một thanh ghi đầu ra.

Bản dựng WCPU-1 này nên được xem như một nguyên mẫu để xác nhận thiết kế và hệ thống dây điện trước khi chuyển sang thiết kế PCB "thực sự".

Tôi đã viết điều này theo kiểu "đừng phạm sai lầm của tôi, cậu bé" theo phong cách chiến tranh, vì vậy đôi khi nó hơi điên rồ và có lẽ hơi xấu hổ, nhưng chúng ta đang ở đây.

Ngoài ra, nó rất, rất dài. Rất tiếc.

Bạn đã thấy "cảnh quay anh hùng" của tòa nhà với tất cả các đèn đỏ trông giống như một cái gì đó trong Upside-Down, nhưng đây là một cảnh quay khác trong ánh sáng ban ngày:

Quá nhiều cho "Không có Breadboard" #

Tất nhiên, ngay khi ra khỏi cổng, tôi đã đưa ra một số quyết định mà cuối cùng cảm thấy như những sai lầm.

Với các sơ đồ thô trong KiCAD (chủ yếu được bắt nguồn từ thiết kế Logisim của tôi, hoạt động tốt như một tài liệu tham khảo), tôi bắt đầu đặt hàng các bộ phận từ Digikey. Nếu bạn lên kế hoạch trước, bạn có thể đạt đến ngưỡng vận chuyển miễn phí, điều mà tôi sẽ giả vờ là chiến lược và không chỉ là kết quả của việc mua quá nhiều đèn LED.

Trong tâm trí của tôi, tôi đã nghĩ rằng tôi muốn tất cả mọi thứ trên bản dựng cuối cùng là Surface Mount Technology (SMT) và vì vậy đó là khá nhiều những gì tôi đã đặt hàng. Tôi sẽ tạo ra một vài PCB và kết nối tất cả chúng lại với nhau (bằng cách nào??) để thử nghiệm/xác nhận ý tưởng. Nhưng cuối cùng có quá nhiều sự sắp xếp lại đến nỗi tôi quyết định chỉ tạo ra một vài PCB (nhiều hơn về điều đó sau) và thực hiện phong cách breadboard còn lại. Chỉ có điều bạn không thể đặt chip SMT vào bảng mạch…

<img src="https://willwarren.com/2026/03/12/building-my-own-cpu-part-3-from-simulation-to-hardware/soldered-smt.jpeg" alt="Ảnh của IS62C256AL được hàn vào bảng chuyển đổi. Kích thước kết hợp lớn hơn gói DIP." style="max-width: 100%;">
Phiên bản DIP cũng sẽ chiếm ít không gian hơn...

Vì vậy, nếu tôi phải làm điều này một lần nữa, tôi sẽ luôn đặt hàng một loạt các bộ phận SMT, nhưng cũng có 2-4 phiên bản DIP của cùng một chip từ cùng một nhà sản xuất để thử nghiệm/xác nhận. Chúng hầu như luôn có sẵn. Nếu tôi sẽ kết thúc bằng cách sử dụng breadboards ở khắp mọi nơi anyway, cũng có thể chỉ cần có được gói NHÚNG cho nguyên mẫu.

Bộ chuyển đổi/bảng đột phá để giải cứu.

PCB tùy chỉnh từ PCBWay #

Tôi đã đặt mua ba PCB tùy chỉnh cho lô đầu tiên:

Hội đồng Lập trình EEPROM #

Đây là bảng đầu tiên tôi cần có vì không có nó, tôi không thể lập trình ROM vi mã và không có gì khác sẽ hoạt động.

Đó là một công cụ độc lập nằm bên ngoài máy tính. Tôi đặt EEPROM vào ổ cắm và kết nối qua serial với máy tính xách tay của mình để tải lên các tệp nhị phân.

<img src="https://willwarren.com/2026/03/12/building-my-own-cpu-part-3-from-simulation-to-hardware/eeprom-programmer.jpeg" alt="Ảnh của lập trình viên EEPROM. Một bản sao Arduino Nano có thể được nhìn thấy ở bên trái và EEPROM có ổ cắm có thể nhìn thấy ở bên phải." style="max-width: 100%;">
Nó trông đẹp nhưng nó có hoạt động không?

Tôi đã nhờ Claude Code giúp tôi thiết kế và triển khai một giao thức nối tiếp để gửi các tệp qua dây và để chúng được ghi vào chip. Điều này kết hợp với hệ thống vi mã hóa mà tôi đã tạo trong python, tạo ra các tệp nhị phân và sau đó cũng kết nối trực tiếp với cổng nối tiếp và tải chúng lên. Nó khá gọn gàng và cho phép lặp lại khá nhanh!

Sai lầm #

Arduino Nano (nhân bản) trên bo mạch được kết nối với tất cả các địa chỉ và dòng dữ liệu thông qua 2 thanh ghi shift.

Nhưng nó cũng được kết nối với các chân điều khiển (OE, WE, CE) thông qua các thanh ghi ca!! Điều đó có nghĩa là ba bit quan trọng nhất của dữ liệu được chuyển ra ngoài cũng kiểm soát thời điểm và cách thức dữ liệu được ghi.

Thật không may, điều này đã hạn chế tốc độ mà tôi có thể ghi vào EEPROM một cách an toàn. Nếu tôi có 3 chân vừa kết nối với GPIO miễn phí trên Arduino, tôi có thể sử dụng khả năng Ghi trang của chip, cho phép ghi waaaay nhanh hơn một byte tại một thời điểm. Trong thử nghiệm của tôi, tôi có thể viết lại toàn bộ EEPROM 8KB trong khoảng 80s một byte tại một thời điểm, và trong khoảng 1.3s với các trang ghi.

Điều đó nói rằng, trong "chế độ chậm", nó đã hoạt động trong lần thử đầu tiên, đó là một chiến thắng trong cuốn sách của tôi.

Hội đồng Đăng ký Chung #

Đây có lẽ là thành công lớn nhất của tôi trong dự án này cho đến nay.

Tôi đã thiết kế một PCB thanh ghi chung chứa một flip flop loại D bát phân 74HC377 (để giữ dữ liệu thực tế) và 74HC245 cho kết nối bus ba chiều của nó.

Bằng cách này, tôi có thể kết nối tất cả các thanh ghi với cùng một bus và phân biệt chúng với các đường điều khiển IN và OUT mà chúng được kết nối. Rất gọn gàng.

<img src="https://willwarren.com/2026/03/12/building-my-own-cpu-part-3-from-simulation-to-hardware/register-pcb.jpeg" alt="Ảnh của PCB Đăng ký chung. Nó có 2 IC lớn trên đó (74HC377 và 74HC245) và 8 đèn LED màu đỏ " style=" max-width: 100%;">
Bạn có thể nói đây là sổ đăng ký hướng dẫn vì việc sử dụng điểm đánh dấu trắng chuyên nghiệp

Khác với các chân IN, OUT và power, bộ 8 chân bên trái là kết nối I/O với 74HC245. Bộ chân bên phải là các chân đầu ra từ 74HC377. Tất nhiên cũng có nhiều đèn nhấp nháy hiển thị trạng thái bên trong của thanh ghi. Siêu tiện dụng để gỡ lỗi!

Ghi chú về 74HC377 #

Trong các bản dựng trong tương lai, tôi có thể sẽ chọn làm việc với 74HC574 thay thế. Lý do là ‘377 không có đầu ra tristate - vì vậy bạn cần một cái gì đó giống như‘245 để kết nối với bus dữ liệu dùng chung, thêm 1 chip bổ sung vào số lượng của bạn.

Hạn chế của một cái gì đó giống như ‘574 là không có cách nào để nhìn thấy trạng thái bên trong mà không xuất ra nó ở đâu đó (như xe buýt). Vì vậy, đối với các dự án gỡ lỗi và trình diễn, 377 vẫn ổn vì bạn có thể kết nối nó với một số đèn LED như tôi đã làm, và sau đó vào bộ thu phát bus, nhưng nếu bạn chỉ sử dụng 574 theo cùng một cách chính xác, bạn CŨNG có tùy chọn để giảm số lượng chip của mình vì bạn không cần 74HC245. Hạn chế rõ ràng là ít đèn nhấp nháy hơn.

Ban này đã làm việc hoàn hảo đầu tiên cố gắng và đã được đá rắn, btw. Không có gì to tát💅.

Bảng Mô-đun Điều Khiển 😩 #

Bảng này cực kỳ đơn giản. Nó chỉ chứa các EEPROM 3x AT28C64B tạo ra từ điều khiển 24 bit.

Nó lấy địa chỉ vào và loại bỏ các bước vi mã, xác nhận/loại bỏ các đường điều khiển và điều khiển toàn bộ máy tính. Đơn giản phải không?

Tôi đã thiết kế sơ đồ và PCB, gửi chúng đến PCBWay và mọi thứ đều ổn!

Sau đó, một loạt những điều tồi tệ đã xảy ra:

  • Các bo mạch đã bị vận chuyển sai trong lần thử đầu tiên bởi PCBWay. Tôi đã nhận được PCB của một số người ngẫu nhiên khác. Đã làm lại và vận chuyển lại, không phải là một thỏa thuận lớn (thêm về điều này bên dưới)
  • Tôi đảo ngược CE trong sơ đồ thực sự hoạt động-HIGH. Vì vậy, trong ROM vi mã, tôi phải đảo ngược nó, một lần nữa
  • Ồ, và rất tiếc, không có tụ điện tách rời ở bất cứ đâu. Tôi đã mua một ít sau đó.
  • Có một lỗ hổng thiết kế lớn khác: các chân Output Enable và Write Enable không được kết nối với bất kỳ thứ gì! Họ chỉ trôi nổi và làm bất cứ điều gì họ muốn, có nghĩa là họ đã tự làm hư hỏng mình liên tục. Tôi đã thực hiện bodge nhỏ nhất thế giới 6 lần và vấn đề đó đã được giải quyết
  • Tôi đã CÀI ĐẶT TẤT CẢ 36 đèn LED NGƯỢC. Từng cái một. Tôi phải xoay chúng riêng lẻ với trạm không khí nóng và nhíp của tôi. Rất zen, nhưng rất, RẤT tẻ nhạt
<img src="https://willwarren.com/2026/03/12/building-my-own-cpu-part-3-from-simulation-to-hardware/control-logic-pcb.jpeg" alt="Ảnh của mô-đun điều khiển PCB đã hoàn thành. Ba EEPROM trong ổ cắm của chúng có thể nhìn thấy được, cùng với thanh ghi 3 ca với các tụ điện tách rời thân của chúng. Một số đèn LED đang phát sáng." style="max-width: 100%;">
PCB này đã đi qua nó

Sau tất cả, trước sự ngạc nhiên của tôi, nó hoạt động hoàn hảo. Hoặc vì vậy tôi nghĩ… (báo trước một lần nữa!!!).

Để xem đánh giá của tôi về các dịch vụ của PCBWay, hãy cuộn xuống gần như hết cỡ.

Quỷ dữ trong thế giới thực (a.k.a. những thứ Logisim đã không cảnh báo tôi về) #

“Just like the simulations” meme

Spoiler : Nó KHÔNG giống như các mô phỏng.

1. Đồng hồ #

Tôi đã chế tạo đồng hồ của mình trên một số bảng perfboard, với một số công tắc nhỏ để lựa chọn giữa một bước, 555 có thể điều chỉnh và bộ dao động tinh thể 1 MHz.

Photo of the clock. It is a messy build on perfboard/veroboard.
Ảnh từ trước khi nó được đồng hóa

Điều đáng ngạc nhiên này thực sự hoạt động tốt! Về cơ bản, tôi có thể đi từ ~ 0,5Hz đến khoảng 450Hz với 555 và nút một bước được gỡ lỗi độc đáo với bộ hẹn giờ 555 khác.

Một vấn đề nhỏ là các công tắc chuyển đổi giữa các chế độ không được gỡ lỗi đúng cách và có thể gây ra sự cố không thường xuyên. Một cách giải quyết là chỉ cần giữ máy tính ở chế độ đặt lại, chọn chế độ và sau đó loại bỏ nó khỏi chế độ đặt lại. Nó chỉ thực sự là một vấn đề đi đến/từ chế độ 1MHz. Tôi sẽ sửa nó theo thỏa thuận thực tế.

Gross Edges #

Mô-đun đồng hồ không tạo ra các cạnh rất đẹp. Cuối cùng, tôi đã khắc phục điều này bằng cách định tuyến đầu ra tới Biến tần Schmitt có độ trễ tích hợp và làm sạch các cạnh đó.

Đường màu vàng ở đây là tín hiệu đồng hồ uể oải. Đây là sự kết hợp của việc phân phối điện kém và hệ thống dây điện kém. Đường màu xanh lam là ví dụ về thiết bị hạ lưu ngẫu nhiên xuống thấp không đúng lúc do “cạnh rơi” ở giữa xung đồng hồ.

Vì vậy, bây giờ dòng chảy từ mô-đun đồng hồ -> biến tần schmitt (tạo ra tín hiệu ~CLK của tôi) -> vào một biến tần Schmitt khác (tạo ra tín hiệu CLK của tôi). Trong các phiên bản mới hơn/tốt hơn, tôi có thể vẫn sẽ sử dụng bộ biến tần Schmitt vì chúng đảm bảo mức chất lượng biên mà chúng tôi mong muốn.

2. Thanh ghi lệnh, Cờ và Thời gian trạng thái T #

Thanh ghi lệnh, Thanh ghi cờ và bộ đếm trạng thái T đều được cấp trực tiếp vào EEPROM và do đó làm cho các đường điều khiển thay đổi. Nếu chúng ta chốt tất cả các thanh ghi ở cạnh lên của tín hiệu CLK thì điều đó sẽ gây ra sự cố.

Sơ đồ thời gian vẽ tay thô sơ hiển thị tín hiệu CLK xung và tín hiệu T và F không tăng ở mức cùng một lúc.
"Sơ đồ thời gian"

Ví dụ: trong sơ đồ tuyệt vời này, T là bộ đếm trạng thái t và F là thanh ghi cờ.

Chúng tôi muốn T AND F thay đổi ở đường màu xanh lá cây (hoặc đường màu xanh lam) KHÔNG ở giữa một hướng dẫn đang diễn ra. Chúng cần phải thay đổi cùng nhau.

Nếu chúng ta có thể di chuyển F trở lại thì điều đó có nghĩa là cạnh xuống của CLK là nơi chúng ta thực hiện tất cả quá trình thiết lập. CLK xuống mức thấp. Sự hỗn loạn xảy ra sau đó. Các dòng điều khiển được xác nhận và xác nhận lại. Dữ liệu được truyền đi trên xe buýt, đôi khi từ nhiều nơi. Ở phía xa, còi báo động.

Cũng cần lưu ý rằng Sổ đăng ký hướng dẫn cũng có vấn đề tương tự! Và chúng ta không thể chỉ theo dõi các thanh ghi này bằng tín hiệu ~CLK vì khi đó chúng sẽ là cả một chu kỳ quá muộn.

Giải pháp #

Để giải quyết vấn đề này, tôi nối các đầu ra của Thanh ghi cờ và Thanh ghi lệnh vào một 74HC377 khác, được đặt xung nhịp với cạnh tăng của tín hiệu ~CLK (cũng là cạnh giảm của tín hiệu CLK). Khi chân Kích hoạt đầu ra được gắn ở mức thấp, chân đồng hồ có toàn quyền kiểm soát thời điểm giá trị đó xuất hiện và bắt đầu điều khiển các EEPROM.

Giờ đây, tất cả sự phức tạp về thời gian thiết lập đều diễn ra cùng một lúc và chúng ta không cần phải lo lắng về việc các đường điều khiển bị hỏng ở giữa lệnh.

3. Trục trặc EEPROM #

Các EEPROM tôi đang sử dụng cho mô-đun điều khiển gặp trục trặc rất nhiều khi địa chỉ đầu vào thay đổi. Đây là một ví dụ hay - đường màu vàng là mã pin địa chỉ đang thay đổi và đường màu xanh lam là EEPROM tạm thời ở mức thấp trong khoảng 25ns.

Bảng dữ liệu cho AT28C64B thực sự đề cập khá tốt đến chủ đề này. Về cơ bản, một khi các chân địa chỉ thay đổi, trong khoảng thời gian lên tới 150ns tiếp theo, BẤT CỨ ĐIỀU GÌ CÓ THỂ XẢY RA. Chân đầu ra ở mức thấp có thể nhấp nháy ở mức cao và sau đó trở lại mức thấp. Chân cao có thể làm điều ngược lại (như trong ảnh của tôi). Trời có thể bắt đầu mưa và bánh mì kẹp thịt sẽ ăn thịt người. Sau khi hết 150ns, mọi thứ đều ổn định và chắc chắn.

Nói chung đây không phải là vấn đề LỚN miễn là toàn bộ hệ thống của bạn đồng bộ và bạn có các giai đoạn riêng biệt để thiết lập và chốt, như tôi đã giải thích ở trên. Về cơ bản, dù sao thì cũng không có gì chốt được bất cứ thứ gì trong thời gian rối loạn này nên không sao cả. Các giá trị trên xe buýt bị bỏ qua. Tất cả đều ổn…

Thậm chí có trục trặc tồi tệ hơn? #

Bây giờ, vì tôi vừa nói rằng trục trặc khi thay đổi địa chỉ là điều bình thường và đã biết, tại sao ĐIỀU NÀY lại xảy ra? 🤔

Đường màu xanh là một trong những đường điều khiển đi ra từ EEPROM. Đường màu vàng là CLK.

Ảnh chụp màn hình máy hiện sóng. Nó tạo ra một sóng vuông (tín hiệu CLK) và một đường khác đang dao động thất thường, thay vì giữ một mức cụ thể.

Và ở đây, một lần nữa, bạn có thể thấy CLK xuống thấp và EEPROM hoạt động điên cuồng chứ không chỉ trong 150ns! Nó cứ trục trặc trong toàn bộ chu kỳ thấp và sau đó cả ở một số thời điểm ngẫu nhiên.

Ảnh chụp màn hình máy hiện sóng. Các trục trặc hiện trở nên tồi tệ hơn và dường như ngẫu nhiên

Đây là ví dụ kỳ lạ nhất mà tôi có thể chụp được vị trí của một trong các dòng điều khiển dao động mãi mãi. Điều này đúng ngay cả khi CLK bị tạm dừng, v.v. những thứ điên rồ.

Ảnh chụp màn hình máy hiện sóng. Hiện tại, các trục trặc này chỉ là vĩnh viễn và không bị ảnh hưởng bởi đồng hồ. Đã xảy ra sự cố.

Vậy thì có gì đáng trách? Kết nối hàn kém 🤦🤦🤦

Có. Không phải một, mà là HAI dòng địa chỉ không có tính liên tục với không phải một, mà là hai trong số EEPROM 🤦🤦🤦🤦🤦🤦🤦🤦

Vì vậy, những dòng địa chỉ đó về cơ bản là trôi nổi, nghĩa là chúng được hiểu là…bất cứ lúc nào…bất cứ lúc nào họ cảm thấy thích.

Tôi đã bán lại các kết nối đó và nó đã trở nên vững chắc kể từ đó 🙃

Tôi luôn luôn, luôn luôn kiểm tra tính liên tục sau khi lắp ráp PCB, nhưng lần này tôi quá hào hứng khi bắt tay vào thực hiện nên đã không làm điều đó và có lẽ tôi phải mất hàng chục giờ để gỡ lỗi các hành vi kỳ lạ. Đừng giống tôi.

Dù sao…

4. Thời gian RAM / Tranh chấp xe buýt / Hỗn loạn không đồng bộ #

Tôi định viết một bài giải thích thật dài về vấn đề này, nhưng thay vào đó tôi nghĩ mình sẽ viết ngắn gọn và thật ngọt ngào để giúp tôi tỉnh táo.

Về cơ bản, mọi thứ được ghi vào RAM đôi khi sẽ hoạt động và đôi khi không. Điều này đang trở thành một chủ đề!

Điều tôi nhận ra bây giờ đã trở nên cực kỳ rõ ràng và tôi cảm thấy thật ngu ngốc vì đã không nhận ra/giải quyết sớm hơn.

Chip RAM tôi đang sử dụng (IS62C256AL) không đồng bộ, nghĩa là nó không có tín hiệu đồng hồ để cho biết khi nào cần thực hiện mọi việc. Nếu bạn muốn nó ghi bất cứ thứ gì có trên bus vào chính nó, bạn hãy để chân ~WE (bật ghi) ở mức thấp, sau đó khi bạn đưa nó lên cao trở lại, dữ liệu sẽ được ghi. Tốt đấy.

Trong thiết kế của tôi, tín hiệu điều khiển RI (RAM IN) được nối trực tiếp đến chân ~WE trên IS62C256AL.

Có lẽ bạn có thể thấy điều này đang diễn ra ở đâu. Tín hiệu điều khiển RI được điều khiển bởi những người bạn trục trặc của chúng ta là EEPROM. Vì vậy, một cách tự nhiên nếu RI gặp trục trặc ở mức cao-thấp-cao hoặc thấp-cao-thấp hoặc bất kỳ kiểu nào khác, chip RAM sẽ lưu trữ mọi thứ có trên các chân I/O của nó ngay lập tức. Những gì có trên các chân I/O của nó tại thời điểm đó rất khó (về mặt thiên văn) không phải là những gì bạn thực sự muốn vào lúc đó.

Giải pháp #

Giải pháp là “cổng” tín hiệu RI bằng tín hiệu đồng hồ của chúng tôi. Điều đó có nghĩa là RAM sẽ hoàn toàn bỏ qua RI cho đến thời điểm chúng ta chọn.

Trong trường hợp thiết kế của tôi, thời điểm chúng ta chọn là cạnh lên của CLK. Đó là thời điểm chúng tôi đã chọn để mọi thứ chốt dữ liệu và RAM cũng không ngoại lệ.

Sơ đồ thời gian ghi vào IS62C256AL. Đây là ảnh chụp màn hình từ biểu dữ liệu.

RAM cam kết dữ liệu trên cạnh tăng của tín hiệu ~WE hoạt động ở mức thấp. Điều đó có nghĩa là chúng ta cần chuyển RI bằng ~CLK để quá trình ghi chỉ hoàn thành vào đúng thời điểm. Điều đó sẽ tạo ra tín hiệu THẤP (bắt đầu quá trình ghi) chỉ khi cả RI VÀ ~CLK đều là thấp. Sau đó, khi ~CLK thay đổi, WE sẽ đạt mức cao trở lại, cam kết ghi vào thời điểm chúng tôi muốn.

Bản sửa lỗi này đã giải quyết được vấn đề cuối cùng đang gây khó khăn cho bản dựng.

Nó hoạt động! #

Cuối cùng, sau khi khắc phục được vấn đề về thời gian của RAM, mọi thứ cuối cùng đã vào đúng vị trí (đồng hồ?).

Máy tính chạy. Ở tần số 1 MHz. Tất cả các chương trình được kiểm tra đều thực hiện chính xác. Nó có thể chạy tốt mà không cần giám sát trong nhiều ngày liền.

23 hướng dẫn, 3 chế độ địa chỉ, 256 byte RAM (hiện tại). Nó đã hoàn thiện Turing.

Fibonacci, vòng lặp đếm, phân nhánh có điều kiện, tất cả đều hoạt động tốt ở tốc độ tối đa.

Tôi phải nói rằng cảm giác nhìn thấy toàn bộ mọi thứ hoạt động hoàn hảo và xử lý bất cứ thứ gì bạn có thể ném vào nó thật tuyệt vời. Đó là một chặng đường dài nhưng tôi đã học được RẤT NHIỀU.

Hãy xem video này về khu rừng chạy chuỗi Fibonacci (vẫn có thanh ghi đầu ra tạm thời dựa trên Arduino):

“Kỹ thuật xây dựng” #

Sau khi khắc phục các vấn đề về thời gian và trục trặc, và máy tính cuối cùng đã ổn định, chúng ta chuyển sang chủ đề khác: làm thế nào mà thứ này thực sự được kết nối với nhau.

Về cơ bản, tôi đặt tiêu đề của phần trong dấu ngoặc kép vì không có kỹ thuật. Tôi chỉ sử dụng dây lõi đặc và nối mọi thứ lại với nhau với chiều dài bất kỳ. Tôi khá lo ngại điều này sẽ hạn chế tốc độ mà tôi có thể chạy máy tính, nhưng thực sự điều đó chỉ có nghĩa là tôi cần kết nối nguồn thực sự tốt trong toàn bộ hệ thống và RẤT NHIỀU tụ điện số lượng lớn và tụ điện bypass (tôi đã sử dụng lần lượt 1uF và 100nF)

Thực sự không có tổ chức và cấu trúc nào, ngoại trừ một vài thứ nằm cùng vị trí.

Đây là bản đồ của sự việc, nhưng hãy cảnh báo: hình ảnh này có thể làm phiền bạn 😂

Một bức ảnh về toàn bộ bản dựng với nhiều khu vực khác nhau được khoanh tròn thô sơ trong mspaint

Trong hình ảnh này, bạn có thể thấy:

  • CLK (the đồng hồ)
  • ~CLK (thực ra chỉ là schmitt kích hoạt cho CLK)
  • KIỂM SOÁT (logic điều khiển dựa trên EEPROM)
  • PC (Bộ đếm chương trình)
  • T (Bộ đếm bước T)
  • BUS (xe buýt)
  • RAM+MAR
  • 1 (ALU, không hiểu tại sao tôi lại đặt 1. Ngoài ra còn có logic phát hiện 0 và bộ thu phát bus của nó)
  • FLAGS (Thanh ghi cờ)
  • IR (Thanh ghi lệnh)
  • IF (74HC377 chuyển IR và FLAGS sang đúng ~pha CLK)
  • X,A (các thanh ghi)
  • B (thanh ghi B cộng với tất cả các cổng XOR được sử dụng cho lệnh SUB)

Tôi sẽ nói rằng tất cả kết hợp với nhau khá nhanh vì tôi không cắt, tước và uốn hàng trăm sợi dây nhỏ đến độ dài hoàn hảo.

Đối với cá nhân tôi, tôi cảm thấy như mình biết rõ thiết kế từ trong ra ngoài nên việc khắc phục sự cố không phải là vấn đề. Nhưng nếu bạn là người mới hoặc đang tìm hiểu, tôi sẽ KHÔNG khuyên bạn nên sử dụng phương pháp "bó dây dẫn khí".

Mỗi dây về cơ bản cũng là một tụ điện, vì vậy, nếu có điện trở tiếp xúc từ các bảng mạch yếu chẳng hạn, thì bạn đã tạo một bộ lọc RC nhỏ xinh sẽ làm chậm các cạnh tín hiệu sắc nét đẹp mắt của bạn thành các đường cong chậm thay vào đó. Vì vậy hãy cẩn thận! Và xác định phạm vi mọi thứ bằng máy hiện sóng nếu bạn có thể!

Arduino Mega: Trình tải ROM đủ tiêu chuẩn nhất thế giới #

Việc sử dụng công tắc DIP để tải chương trình vào RAM đã trở nên lỗi thời rất nhanh. Vì chiếc máy này có 256 byte RAM có thể sử dụng được nên các chương trình có thể hơi dài.

Thay vào đó, tôi đã hack một Arduino Mega vào giữa nó.

Nó được kết nối trực tiếp với bus và một số đường điều khiển (RESET, II, RI, MI, CLK).

Tôi cũng định tuyến đường dây CLK thông qua một công tắc SPDT nhỏ để kiểm soát xem CLK đến từ đồng hồ thực tế hay từ Arduino.

Khi khởi động, Arduino kéo thiết lập lại xuống mức thấp, sau đó đẩy từng byte vào RAM, tạo xung CLK khi nó hoạt động, sau đó giải phóng dòng thiết lập lại và đặt tất cả các kết nối dòng điều khiển thành “INPUT” (làm cho chúng trở thành High-Z, rút phích cắm chúng khỏi mạch một cách hiệu quả).

Vì vậy, quá trình tải chương trình là:

  • Chuyển dòng CLK sang Arduino
  • Bật nguồn WCPU-1 nếu không phải chưa
  • Nhấn nút đặt lại trên Arduino
  • Arduino đưa chương trình vào RAM trong khoảng 10ms
  • Giữ nút đặt lại WCPU-1
  • Chuyển CLK trở lại đồng hồ thực
  • Bỏ nút đặt lại

Điều này không phải lúc nào cũng hoạt động tốt và thành thật mà nói, đây là một một vụ hack lớn. Các mức logic trên các đường điều khiển ở khắp mọi nơi vì EEPROM cũng đang cố gắng điều khiển các đường này.

Trong thực tế, việc đấu tranh trên bus này ban đầu đã ngăn cản Arduino ghi vào RAM. Vì vậy, trong hình ảnh trên, bạn có thể thấy một thứ được đánh dấu LOAD chỉ là một 74HC245 có chân Kích hoạt đầu ra được điều khiển bởi Arduino.

Bằng cách này, Arduino có thể tạm thời cắt EEPROM khỏi dòng RI khi nó đang hoạt động và sau đó nó sẽ từ bỏ nó trở lại sau đó. Dường như không có tín hiệu điều khiển nào khác quan tâm đến Arduino, nhưng RI cực kỳ nhạy cảm.

Cách thích hợp để thực hiện việc này có lẽ là nối chân OE của tất cả các EEPROM logic điều khiển với Arduino, sau đó bạn có thể “rút phích cắm” toàn bộ mô-đun khỏi máy tính một cách hiệu quả trong khi trình tải Arduino thực hiện công việc đó. Thật không may cho tôi, tôi đã không tháo chốt OE trên PCB Mô-đun điều khiển của mình!

Giải pháp “thực sự” #

Mục tiêu của tôi ở đây là loại bỏ Arduino hoàn toàn. Tôi sẽ chia RAM có thể định địa chỉ thành 2 khối 128 byte với khối đầu tiên được nối với (một) EEPROM khác.

Sau đó, chương trình có thể tồn tại vĩnh viễn trong EEPROM và khi khởi động, chương trình sẽ ở đó.

Tôi thực sự muốn WCPU-1 trở thành một dạng trình diễn một bảng. Vì vậy, nó chỉ chạy các chương trình cơ bản tương đối nên tôi thấy ổn với việc mất RAM.


Rolling My Own Toolchain #

OK hiện tại Arduino đang đưa các chương trình vào RAM. Nhưng những chương trình đó là gì? Chúng hoạt động như thế nào? Tôi đang viết mã như thế nào? Làm cách nào để tạo hình ảnh vi mã cho các EEPROM bị trục trặc?

Tôi rất vui vì bạn đã hỏi.

Trình tạo vi mã #

Đó chỉ là một tập lệnh Python rất đơn giản để xây dựng một mảng lớn và chuyển nó thành ba tệp nhị phân (rom0.bin, rom1.bin, rom2.bin), một tệp cho mỗi EEPROM. Mỗi EEPROM chịu trách nhiệm cho 8 tín hiệu điều khiển. Cuối cùng ROM2 có một vài cái chưa được sử dụng mà tôi có thể sử dụng cho chức năng mới trong tương lai.

Mỗi lệnh được xác định là danh sách các tổ hợp tín hiệu điều khiển trên mỗi bước T. Ví dụ NOP chỉ là [CO | MI, RO | II | CE, N]. Nó đọc hơi giống mã giả để biết phần cứng sẽ làm gì vào bất kỳ thời điểm nào.

Một phần khó khăn là các lệnh có điều kiện. Tôi áp dụng mặt nạ cho các bit Cờ để cùng một mã opcode có thể có mã vi mô hoàn toàn khác nhau tùy thuộc vào cờ nào được đặt. JC (nhảy nếu mang) theo nghĩa đen có hai trình tự khác nhau được đưa vào hình ảnh. Một trong số chúng tải địa chỉ mới vào PC và một cái chỉ bỏ qua toán hạng.

EEPROM có tổng cộng 13 dòng địa chỉ và tôi trình bày chúng như thế này:

SZC IIIIII TTTT

SZC là các cờ Sign, ZeroCarry. I là 6 bit của lệnh hiện tại và T là 4 bit của trạng thái t. Vì vậy, tôi có thể có 64 hướng dẫn khác nhau, mỗi hướng dẫn có tối đa 16 bước vi mã. Có thể là quá mức cần thiết.

Bộ hướng dẫn #

Tôi quyết định giữ nó đơn giản vì tôi không có ý định bổ sung quá nhiều khả năng và tôi mong đợi các chương trình sẽ có trong đó WCPU tương đối đơn giản. Tôi có không gian cho 64 mã hoạt động khác nhau và hiện tại tôi có 23 mã.

Mặc dù đơn giản nhưng bạn có thể tìm thấy một số cách khá sáng tạo để sử dụng những hướng dẫn này để tạo ra các chương trình thú vị. Ngoài ra còn có các chế độ đánh địa chỉ tức thời và tuyệt đối cho nhiều lệnh. Nghĩa là chúng có thể hoạt động trên một giá trị bằng chữ được cung cấp như 5 hoặc một giá trị được tìm nạp từ nơi khác trong bộ nhớ như $AA.

Hãy kiểm tra nó out!

OpcodeMnemonicOperandMô tảFlagsMicrosteps
0x00NOPKhông hoạt động3
0x01 HLTTạm dừng CPU1
0x02OUTXuất thanh ghi A tới hiển thị3
0x04ADDimmA = A + ngay lập tứcC, Z, S5
0x05ADDabsA = A + [địa chỉ]C, Z, S6
0x06SUBimmA = A - ngay lập tứcC, Z, S5
0x07SUBabsA = A - [địa chỉ]C, Z, S6
0x08CMPimmĐặt cờ từ A - ngay lập tức (loại bỏ kết quả)C, Z, S5
0x09 CMPabsĐặt cờ từ A - [địa chỉ] (loại bỏ kết quả)C, Z, S6
0x14LDAimmTải ngay vào A4
0x15LDAabsTải [địa chỉ] vào A5
0x16LDBimm Tải ngay vào B4
0x17LDBabsTải [địa chỉ] vào B5
0x18LDXimmTải ngay vào X4
0x19LDXabsTải [địa chỉ] vào X5
0x20 STAabsLưu A vào [địa chỉ]5
0x21STBabsLưu B vào [địa chỉ] (chưa có trong phần cứng, không chắc liệu tôi có care)
0x22STXabsLưu X vào [địa chỉ]5
0x30JMPabs Nhảy vô điều kiện4
0x33JCabsNhảy nếu mang = 14
0x34JNCabsNhảy nếu mang = 04
0x35JZabsNhảy nếu không = 14
0x36JNZ absNhảy nếu Zero = 04
0x37JSabsNhảy nếu Dấu = 14
0x38JNSabsNhảy nếu Dấu = 04

Trình biên dịch (wcasm ) #

Có một bộ hướng dẫn cũng tốt thôi, nhưng bạn vẫn phải viết mã như thế này:

0x14
0x01
0x04
0x01
0x02
0x30
0x02

Điều đó chẳng vui chút nào.

Bạn biết điều gì thú vị hơn không?

Ảnh chụp màn hình của Neovim với chủ đề tuyệt vời của Will được áp dụng. Nó hiển thị một số mã lắp ráp kiểu 6502, cú pháp được đánh dấu độc đáo. Mã hiển thị tính toán chuỗi Fibonacci trong một vòng lặp.

Đánh dấu cú pháp tùy chỉnh, nhận xét, “biến” và có thể viết mã theo cách thuận tiện.

Để biến tệp .w được đánh dấu bằng cú pháp tùy chỉnh thú vị này thành định dạng nhàm chán hơn mà máy tính có thể hiểu được, chúng ta cần một trình biên dịch mã.

Tuyên bố từ chối trách nhiệm hoàn toàn Tôi đã nhận được một số trợ giúp từ người bạn Claude Code của mình để vượt qua một số bản tóm tắt và chi tiết vụn vặt về mã hóa mà tôi thường không thích. Nó cũng tạo ra tất cả cấu hình đánh dấu cú pháp cho thiết lập neovim của tôi (bạn có thể tìm thấy tại đây!)

Tôi đã viết wcasm bằng Python và nó chiếm trong tài khoản của tôi .w và xuất ra các tệp nhị phân thô, đồng thời chỉ in ra tất cả mã máy (haha) mà tôi có thể sao chép và dán vào bản phác thảo Arduino để chạy trên máy tính. Trong tương lai, tôi sẽ lấy các tệp nhị phân này và gửi chúng tới EEPROM thông qua Trình lập trình EEPROM được mô tả trước đó.

Tôi đã sử dụng cú pháp 6502-ish và muốn có các nhận xét cũng như biến và điều đó giúp bạn viết các chương trình phức tạp hơn mà không bị mất trí dễ dàng hơn.

Trình biên dịch mã sử dụng cú pháp để tìm ra mã opcode thực tế mà bạn muốn. Ví dụ: lda #5 là “tải thanh ghi A có 5” có mã opcode 0x14. Tương tự, lda $e1 sẽ tải A với giá trị được lưu trong RAM tại địa chỉ e1.

Nó thực hiện hai lượt, lượt đầu tiên xóa nhận xét và khoảng trắng, đồng thời ghi lại vị trí của tất cả các nhãn (như loop: ở trên). Bước thứ hai chuyển đổi tất cả các mã hoạt động và thay thế các biến và nhãn bằng địa chỉ thực.

Đường dẫn đầy đủ #

Đáng đánh vần từ đầu đến cuối vì mặc dù nó thật khó chịu, nhưng vẫn rất hài lòng:

  1. Viết tập hợp trong tệp .w
  2. wcasm.py lắp ráp nó thành một .bin
  3. Mã máy được nhúng trong bản phác thảo Arduino
  4. Tải bản phác thảo lên Arduino với CLK ở “chế độ Arduino”
  5. Arduino tải chương trình vào RAM, khởi động lại
  6. Chuyển CLK trở lại Đồng hồ và CPU sẽ chạy chương trình!

Có rất nhiều bước nhưng mỗi bước đều rất đơn giản và có thể kiểm tra riêng lẻ. Tất nhiên, trong tương lai, Arduino sẽ không còn nữa và wcasm sẽ được cải tiến để gửi tệp nhị phân thẳng đến EEPROM thông qua nối tiếp.

Ngoài ra còn có rất nhiều cách khác để làm cho nó đẹp hơn trong tương lai, nhưng tôi có thể lưu cách đó cho WCPU-2 😉.

Vậy là xong rồi à? #

Không. Có một vài điều lớn còn thiếu trước khi tôi muốn gọi điều này là “đã hoàn thành”. Có rất nhiều thứ nhỏ nhặt nhưng tôi sẽ chỉ liệt kê những mục còn thiếu lớn nhất.

Không có đầu ra (lol!) #

Có, có lẽ là một trong những thứ nhất thiếu các thành phần quan trọng và hữu hình.

Có, máy tính vẫn hoạt động. Không, nó không thể hiển thị bất cứ thứ gì.

Tôi đã sử dụng Arduino thứ hai với màn hình OLED (xem video ở trên) để giả làm thanh ghi đầu ra trong một thời gian, nhưng cuối cùng tôi chỉ xem thanh ghi A giống như một kẻ điên.

Tôi đã học được cách đọc nhị phân trong nháy mắt khi làm việc này, điều này thật buồn cười.

Thật là một điều ngu ngốc khi không xây dựng.

Tình huống của trình tải Arduino + phân chia RAM #

Tôi đã giải thích điều này khá rõ ở trên, nhưng tóm lại, tôi muốn loại bỏ mọi Arduinos trong bản dựng và dựa vào thay vào đó là logic và EEPROM rời rạc, đồng thời làm cho toàn bộ mọi thứ trở nên khép kín và tự quản lý. 128 byte RAM và 128 byte ROM. Bật máy lên là máy chạy, thật dễ dàng!

Không có HLT #

Không chắc tại sao tôi chưa bao giờ kết nối thiết bị này, nhưng chúng ta bắt đầu. Tôi chỉ cần VÀ tín hiệu đồng hồ đến có tín hiệu ~HLT và điều đó sẽ thực hiện được! Đúng không?!

Bật nguồn/Đặt lại #

Nếu không có trình tải Arduino, tôi sẽ cần một cách để đặt IR, FLAGS, PC và T-State thành một trạng thái đã biết trước khi bắt đầu thực thi mã từ ROM. Tôi đã nghe nói đến một số IC tốt có thể trợ giúp vấn đề này nhưng tôi chưa thực hiện nhiều nghiên cứu.

Thay thế Sign Flag bằng Overflow Flag #

Hiện tại MSB của kết quả ALU cuối cùng được chốt làm cờ dấu, hoạt động nhưng tôi không thực sự quan tâm đến nó nhiều.

Tôi nghĩ rằng cờ tràn (V) sẽ tốt hơn và hữu ích hơn. Sau đó, bạn có thể xem liệu kết quả ALU của mình có nằm ngoài phạm vi có thể biểu thị hay không. Cần thêm một vài cổng để triển khai nhưng cũng không quá tệ.

Đồng hồ tốt hơn #

Không có sự chuyển đổi giữa các chế độ tốc độ là một điều đáng tiếc, vì vậy tôi muốn khắc phục điều đó trước khi tôi hoàn thành thiết kế PCB cuối cùng. Nói về…

PCB “Cuối cùng” #

Tôi muốn đưa tất cả những thứ này vào một PCB độc lập. Tôi muốn nó thực sự “chuyển tiếp bằng đèn LED” và thực sự có tính tương tác và xúc giác. Có lẽ tôi thậm chí sẽ đóng khung nó hoặc đặt nó trên tủ đầu giường của mình, ai biết được?

Tiếp theo là gì? #

Bạn có thể mong đợi Phần 4, trong đó hy vọng tôi sẽ giải quyết được tất cả các tính năng và thành phần còn thiếu, đồng thời xây dựng phiên bản đầu tiên và hy vọng là phiên bản cuối cùng của PCB WCPU-1 chính thức.

Sau đó…tất nhiên là WCPU-2! Tôi có một danh sách dài những thứ mong muốn dành cho WCPU-2 bao gồm nhưng không giới hạn ở:

  • Các bus riêng biệt: bus địa chỉ 16 bit, bus dữ liệu 8 bit
  • Con trỏ ngăn xếp 16 bit và bộ đếm chương trình
  • ALU có khả năng cao hơn: AND/OR/NAND/NOR/NOT/XOR/SHL/SHR, v.v.
  • nhiều hơn thế nữa……

Tôi muốn chuyển sang lãnh thổ “máy tính thực” và điều đó làm tôi phấn khích vô cùng.

Nguồn mở #

Tôi sẽ chia sẻ mọi thứ trên của mình Github, nhưng chưa.

Dự án hiện là một mớ hỗn độn khó hiểu của các tệp trong khoảng 12 thư mục khác nhau nằm rải rác trên 2 máy tính khác nhau 😭

Nhưng vâng, tôi có kế hoạch mở nguồn toàn bộ mọi thứ, bao gồm chuỗi công cụ, tệp thiết kế PCB đầy đủ và BOM để bạn có thể tự tạo và lập trình nó một cách dễ dàng, nếu bạn muốn.

Kết luận #

Dự án này đã được thực hiện trong một thời gian dài và đòi hỏi một lượng lớn năng lượng tinh thần. Đôi khi tôi chỉ ngồi đó suy nghĩ về các pha của đồng hồ từ lâu, hoặc tự hỏi về sự trục trặc của EEPROM khi tắm như một người hoàn toàn bình thường.

Một dự án như thế này có thể là một cái lỗ thỏ khổng lồ. Phần khó nhất là biết khi nào nên ngừng thêm tính năng. Tôi đã tiến rất gần đến việc thêm một ngăn xếp và con trỏ ngăn xếp vào WCPU-1, nhưng cuối cùng, tôi cảm thấy mình muốn có nhiều RAM hơn, có thể là ngân hàng, rồi GPIO, v.v., v.v., điều đó không bao giờ kết thúc. Vì vậy, biết nơi để cắt nó là một ý tưởng tốt. Hãy giữ phạm vi đó ở mức tối thiểu!

Tôi đã học được một lượng kiến ​​thức khổng lồ thông qua dự án này và cho đến nay nó vẫn cực kỳ bổ ích và tôi nghĩ nó sẽ tiếp tục như vậy ☺️.

Đối với dự án tiếp theo, trước khi mua nhiều thứ hoặc xây dựng một rừng dây khổng lồ khác để phục vụ WCPU-2, tôi sẽ xem xét quá trình phát triển FPGA và thử xây dựng WCPU-1 trên đó. Từ đó, hy vọng tôi có thể sử dụng nó để nhanh chóng tạo nguyên mẫu WCPU-2 và hoàn thiện thiết kế hoàn chỉnh trước khi chuyển sang các bộ phận thực tế.

Bây giờ hãy nói về PCBWay! #

Tiết lộ: PCBWay đã liên hệ để tài trợ cho dự án này. Họ cung cấp miễn phí việc chế tạo và vận chuyển PCB cho các bo mạch được mô tả trong phần này. Tuy nhiên, họ muốn tôi trung thực nhất có thể.

Tất cả ý kiến, sai sót và đèn LED ngược đều là của riêng tôi.

The Good #

Bản thân PCB có chất lượng tuyệt vời. Kết thúc thực sự tốt đẹp, màn hình lụa rõ ràng, quay vòng nhanh. Tất cả những điều tôi mong đợi. Những lỗi chính trên bo mạch EEPROM hoàn toàn là lỗi của tôi. Các bảng được chế tạo đúng như những gì tôi thiết kế.

Tương tác với dịch vụ khách hàng diễn ra nhanh chóng và rõ ràng, đồng thời khiến mọi việc diễn ra nhanh chóng.

The Less Good #

Các bảng Đăng ký và Lập trình viên EEPROM được đựng trong một hộp có PCB của người khác thay vì các bảng Mô-đun Điều khiển của tôi, điều này khiến tôi mất vài ngày.

PCBWay đề nghị làm lại và gửi lại các bảng này miễn phí, điều này thật tuyệt vời! Họ thật không thể tin được chủ động về việc này ngay khi tôi báo cáo vấn đề và bắt đầu sản xuất lô mới ngay lập tức. Các bảng mới tôi đã rơi vào tay tôi 3 ngày sau khi gửi email cho họ về vấn đề này.

Tôi đã phải đóng thuế nhập khẩu lần thứ hai, điều này thật buồn cười, nhưng tôi đã thông báo cho bộ phận dịch vụ khách hàng và họ đã ghi có số tiền đó trở lại tài khoản PCBWay của tôi ngay lập tức, điều này thật tuyệt vời.

Kết luận #

Dịch vụ chế tạo PCB của PCBWay nói chung là tuyệt vời. Tôi muốn giới thiệu cho bất kỳ ai đang thực hiện công việc sở thích với khối lượng thấp chỉ với một số lưu ý được liệt kê ở trên. Lỗi vận chuyển cắn tôi không phải phổ biến, tôi chỉ xui xẻo thôi.

Cảm ơn bạn đã đọc! #

Tôi không thể tin được là bạn đã đọc hết đến cuối!

Hẹn gặp lại bạn ở phần 4 😎

💾


Bạn có thể xem tất cả các bài đăng trong loạt bài này tại /tags/wcpu-1.

Hãy đến thưởng thức Mastodon hoặc Bluesky!

Tác giả: wwarren

#discussion