Biên dịch mã để chạy từ RAM ngoài


13

Tôi đang xem xét các thiết kế cho một hệ thống trò chơi tối giản dựa trên PIC18F85J5. Một phần trong thiết kế của tôi là các trò chơi có thể được tải từ thẻ SD mà không cần lập trình lại chip hoặc flash bộ nhớ chương trình. Tôi đã chọn con chip đó vì nó có giao diện bộ nhớ ngoài cho phép tôi chạy mã từ SRAM bên ngoài.

Ý tưởng cơ bản là bộ nhớ chương trình bên trong sẽ chứa giao diện để duyệt thẻ sd và khi người dùng chọn chương trình, nó sẽ sao chép tệp hex từ thẻ sd sang ram ngoài, sau đó nhảy thực thi vào không gian ram bên ngoài .

Bộ nhớ chương trình nội bộ cũng sẽ có các thư viện khác nhau cho đồ họa, đầu vào bộ điều khiển và các tiện ích khác nhau.

Tôi khá tự tin Tôi biết làm thế nào để các phần firmware bên trong hoạt động tốt. Vấn đề là tạo chương trình để chạy từ RAM ngoài. Nó không cảm thấy giống như nhắm mục tiêu một pic thông thường và nó cần phải nhận thức được các chức năng thư viện có sẵn trong bộ nhớ trong, nhưng không biên dịch lại chúng, chỉ liên kết với chúng. Nó cũng cần bắt đầu sử dụng địa chỉ ngay sau 32k flash nội bộ, không phải ở mức 0. Có cách nào tốt để biên dịch chương trình bằng các loại ràng buộc này không?

Tôi đang sử dụng MPLab IDE, nhưng tôi không quen thuộc lắm với nó, hoặc làm thế nào để thực hiện loại tùy chỉnh này.


Một trong những câu hỏi hay nhất mà tôi đã thấy ở đây trong một thời gian ... Tôi mong muốn được nghe những ý tưởng và câu trả lời.
Jon L

Một số cách tiếp cận thay thế thú vị được thảo luận trong Electronics.stackexchange.com/questions/5386/iêu
Toby Jaffey

Tôi đã thấy điều đó, nhưng họ chủ yếu khuyên bạn nên viết bằng flash, điều mà tôi muốn tránh. Thiết kế phần cứng của tôi sẽ giống như hình 6 trong ghi chú ứng dụng trong câu trả lời được chấp nhận.
captncraig

Câu trả lời:


8

Bạn có hai vấn đề riêng biệt:

  1. Xây dựng mã cho phạm vi địa chỉ RAM bên ngoài.

    Điều này thực sự rất dễ dàng. Tất cả bạn phải làm là tạo một tệp liên kết chỉ chứa các phạm vi địa chỉ mà bạn muốn mã chiếm. Lưu ý rằng bạn không chỉ cần dành một dải địa chỉ bộ nhớ chương trình cụ thể cho các ứng dụng bên ngoài này mà còn cần một số dung lượng RAM. Không gian RAM này, giống như các địa chỉ bộ nhớ chương trình, cần phải được sửa và biết. Chỉ cần tạo các phạm vi địa chỉ cố định và đã biết có sẵn để sử dụng trong tệp liên kết. Đừng quên làm cho chúng KHÔNG có sẵn trong tệp liên kết mã cơ sở.

    Sau khi mã cơ sở tải một ứng dụng mới vào bộ nhớ ngoài, nó phải biết cách thực thi nó. Điều dễ nhất có lẽ là bắt đầu thực hiện tại vị trí RAM ngoài đầu tiên. Điều này có nghĩa là mã của bạn sẽ cần một phần CODE tại địa chỉ bắt đầu tuyệt đối đó. Điều này có chứa một GOTO đến nhãn bên phải trong phần còn lại của mã, tất cả sẽ được định vị lại.

  2. Liên kết các ứng dụng với thói quen thư viện trong mã cơ sở.

    Không có cách đơn giản nào ngay lập tức để làm điều này với các công cụ Microchip hiện có, nhưng nó cũng không tệ.

    Một vấn đề lớn hơn nhiều là cách bạn muốn đối phó với những thay đổi mã cơ sở. Chiến lược đơn giản là xây dựng mã cơ sở của bạn, chạy một chương trình trên tệp bản đồ kết quả để thu hoạch địa chỉ toàn cầu, sau đó yêu cầu nó viết một tệp nhập với các câu lệnh THIẾT BỊ cho tất cả các ký hiệu được xác định toàn cầu. Tập tin nhập này sau đó sẽ được bao gồm trong tất cả các mã ứng dụng. Không có gì để liên kết, vì mã nguồn ứng dụng về cơ bản chứa các tham chiếu địa chỉ cố định đến các điểm nhập mã cơ sở.

    Điều đó dễ làm và sẽ hoạt động, nhưng hãy xem xét những gì xảy ra khi bạn thay đổi mã cơ sở. Ngay cả một sửa lỗi nhỏ cũng có thể khiến tất cả các địa chỉ di chuyển xung quanh, và sau đó tất cả mã ứng dụng hiện tại sẽ không tốt và phải được xây dựng lại. Nếu bạn không bao giờ có kế hoạch cung cấp cập nhật mã cơ sở mà không cập nhật tất cả các ứng dụng, thì có lẽ bạn có thể thoát khỏi điều này, nhưng tôi nghĩ đó là một ý tưởng tồi.

    Cách tốt hơn là có một khu vực giao diện được xác định tại một địa chỉ đã biết cố định đã chọn trong mã cơ sở. Sẽ có một GOTO cho mỗi chương trình con mà mã ứng dụng có thể gọi. Các GOTO này sẽ được đặt tại các địa chỉ đã biết cố định và các ứng dụng bên ngoài sẽ chỉ gọi đến các vị trí đó, sau đó sẽ nhảy đến bất cứ nơi nào chương trình con thực sự kết thúc trong bản dựng mã cơ sở đó. Chi phí này có 2 từ bộ nhớ chương trình cho mỗi chương trình con xuất khẩu và hai chu kỳ bổ sung khi chạy, nhưng tôi nghĩ nó rất xứng đáng.

    Để thực hiện quyền này, bạn cần tự động hóa quá trình tạo GOTO và tệp xuất kết quả mà các ứng dụng bên ngoài sẽ nhập để lấy địa chỉ chương trình con (thực sự là chuyển hướng GOTO). Bạn có thể làm được với một số cách sử dụng macro MPASM thông minh, nhưng nếu tôi đang làm điều này, tôi chắc chắn sẽ sử dụng bộ tiền xử lý của mình vì nó có thể ghi vào tệp bên ngoài trong thời gian tiền xử lý. Bạn có thể viết một macro tiền xử lý để mỗi bộ chuyển hướng có thể được xác định bởi một dòng mã nguồn duy nhất. Macro thực hiện tất cả những thứ khó chịu dưới mui xe, đó là tạo GOTO, tham chiếu bên ngoài cho thói quen đích thực tế và thêm dòng thích hợp vào tệp xuất với địa chỉ không đổi đã biết của thường trình đó, tất cả đều có tên thích hợp. Có lẽ macro chỉ tạo ra một loạt các biến tiền xử lý với các tên thông thường (giống như một mảng có thể mở rộng thời gian chạy), và sau đó tệp xuất được viết một lần sau tất cả các lệnh gọi macro. Một trong nhiều điều mà bộ xử lý trước của tôi có thể làm mà các macro MPASM không thể thực hiện là thao tác chuỗi để xây dựng các tên biểu tượng mới từ các tên khác.

    Bộ tiền xử lý của tôi và một loạt các công cụ liên quan khác có sẵn miễn phí tại www.embedinc.com/pic/dload.htm .


Tôi thực sự thích ý tưởng về một bàn nhảy cố định. Tôi chỉ có thể bắt đầu từ cuối bộ nhớ flash và có các vị trí cố định cho mỗi cuộc gọi hệ thống. Tôi thậm chí có thể thoát khỏi một tệp tiêu đề được duy trì thủ công với địa chỉ của tất cả các chương trình con nếu tôi không thể tìm ra tất cả các voodoo tiền xử lý mà bạn mô tả.
captncraig

5

Cách 1: Ngôn ngữ được giải thích

Điều này không trả lời trực tiếp câu hỏi (đó là một câu hỏi xuất sắc, BTW và tôi hy vọng sẽ học được từ một câu trả lời trực tiếp giải quyết nó), nhưng nó rất phổ biến khi thực hiện các dự án có thể tải các chương trình bên ngoài để viết các chương trình bên ngoài một ngôn ngữ diễn giải. Nếu tài nguyên eo hẹp (chúng sẽ có trên bộ xử lý này, bạn đã nghĩ đến việc sử dụng bộ xử lý PIC32 hoặc ARM nhỏ cho việc này chưa?), Việc giới hạn ngôn ngữ trong một tập hợp con của thông số kỹ thuật đầy đủ là điều phổ biến. Thậm chí xa hơn trong chuỗi là các ngôn ngữ dành riêng cho tên miền chỉ làm một vài điều.

Ví dụ, dự án elua là một ví dụ về ngôn ngữ được giải thích tài nguyên thấp (RAM 64 kB). Bạn có thể giảm xuống còn 32k RAM nếu bạn loại bỏ một số tính năng (Lưu ý: Nó không hoạt động trên bộ xử lý hiện tại của bạn, đó là kiến ​​trúc 8 bit. Sử dụng RAM ngoài có thể sẽ quá chậm đối với đồ họa). Nó cung cấp một ngôn ngữ nhanh, linh hoạt trong đó người dùng mới có thể dễ dàng lập trình trò chơi nếu bạn cung cấp API tối thiểu. Có rất nhiều tài liệu có sẵn cho ngôn ngữ trực tuyến. Có những ngôn ngữ khác (như Forth và Basic) mà bạn có thể sử dụng theo cách tương tự, nhưng tôi nghĩ rằng Lua là lựa chọn tốt nhất vào lúc này.

Trong một tĩnh mạch tương tự, bạn có thể tạo ngôn ngữ dành riêng cho tên miền của riêng bạn. Bạn sẽ phải cung cấp API đầy đủ hơn và tài liệu bên ngoài, nhưng nếu các trò chơi hoàn toàn giống nhau thì điều này sẽ không quá khó khăn.

Trong mọi trường hợp, PIC18 có thể không phải là bộ xử lý mà tôi sử dụng cho một cái gì đó liên quan đến lập trình / kịch bản và đồ họa tùy chỉnh. Bạn có thể quen thuộc với lớp bộ xử lý này, nhưng tôi đề nghị rằng đây sẽ là thời điểm tốt để sử dụng một cái gì đó với trình điều khiển hiển thị và nhiều bộ nhớ hơn.

Cách 2: Chỉ cần lập trình lại toàn bộ

Tuy nhiên, nếu bạn đã có kế hoạch tự lập trình tất cả các trò chơi trong C, thì đừng bận tâm đến việc chỉ tải logic trò chơi từ thẻ SD. Bạn chỉ cần 32kB Flash để lập trình lại và có thể dễ dàng nhận được thẻ nhớ 4 GB cho việc này. (Lưu ý: thẻ lớn hơn thường là SDHC, khó giao tiếp hơn). Giả sử rằng bạn sử dụng mọi byte cuối cùng trong 32 kB của mình, sẽ chừa chỗ trên thẻ SD cho 131.072 bản sao chương trình cơ sở của bạn với bất kỳ logic trò chơi nào bạn cần.

Có rất nhiều chú thích để viết bộ tải khởi động cho PIC, như AN851 . Bạn cần thiết kế bộ tải khởi động của mình để chiếm một vùng bộ nhớ cụ thể (có thể là đỉnh của vùng nhớ, bạn sẽ chỉ định điều này trong trình liên kết) và chỉ định rằng các dự án phần sụn đầy đủ không đến được vùng này. Các appnote đánh vần điều này chi tiết hơn. Chỉ cần thay thế "Phần khởi động của PIC18F452" bằng "Phần khởi động tôi chỉ định trong trình liên kết" và tất cả sẽ có ý nghĩa.

Sau đó, bộ tải khởi động của bạn chỉ cần cho phép người dùng chọn một chương trình để chạy từ thẻ SD và sao chép toàn bộ nội dung. Một giao diện người dùng có thể là người dùng phải giữ một nút ấn để vào chế độ lựa chọn. Thông thường, bộ nạp khởi động sẽ chỉ kiểm tra trạng thái của nút này khi thiết lập lại và nếu không được nhấn, hãy khởi động vào trò chơi. Nếu nó được giữ, nó sẽ cần cho phép người dùng chọn một tệp trên thẻ SD, sao chép chương trình và tiếp tục khởi động vào trò chơi [mới].

Đây là khuyến nghị hiện tại của tôi.

Tùy chọn 3: Phép thuật sâu liên quan đến việc chỉ lưu trữ một phần của tệp hex

Vấn đề với cơ chế được hình dung của bạn là bộ xử lý không xử lý các lệnh gọi API và hàm, nó xử lý các số - địa chỉ mà con trỏ lệnh có thể nhảy và dự kiến ​​sẽ có mã thực hiện lệnh gọi hàm theo thông số API. Nếu bạn cố gắng biên dịch chỉ là một phần của chương trình, trình liên kết sẽ không biết phải làm gì khi bạn gọi check_button_status()hoặc toggle_led(). Bạn có thể biết rằng các hàm đó tồn tại trong tệp hex trên bộ xử lý, nhưng nó cần biết chính xác địa chỉ mà chúng cư trú.

Trình liên kết đã chia mã của bạn thành nhiều phần; bạn về mặt lý thuyết có thể phá vỡ này thành các phần bổ sung với một số -section#pragmanhững câu thần chú. Tôi chưa bao giờ làm điều này, và không biết làm thế nào. Cho đến khi hai phương pháp trên làm tôi thất bại (hoặc ai đó đăng câu trả lời tuyệt vời ở đây), tôi có thể sẽ không học cơ chế này và vì vậy tôi không thể dạy nó cho bạn.


Phản đối của tôi đối với số 2 là bộ nhớ flash có số chu kỳ xóa giới hạn trong vòng đời của chip. Tôi không muốn sử dụng mcu cowier vì tôi sẽ tối giản 8 bit.
captncraig

@CMP - Nó có ít nhất 10.000 chu kỳ xóa. Nếu ai đó chơi một trò chơi khác nhau mỗi ngày, nó sẽ kéo dài đến năm 2039. Flash gần như chắc chắn sẽ tồn tại lâu hơn các phần còn lại của mạch. Tôi không nghĩ rằng bạn cần phải lo lắng về điều này trừ khi nó được chơi trong một trò chơi arcade hàng chục lần mỗi ngày.
Kevin Vermeer

1
Thứ hai, tối giản 8 bit có thể trông rất tuyệt, nhưng nó rất hấp dẫn cho lập trình. Dễ dàng hơn nhiều để có được một bộ vi điều khiển mạnh mẽ và làm cho nó trông có vẻ cổ điển hơn là buộc phải làm cho nó trông thật cổ điển vì bạn đang đẩy các giới hạn của bộ xử lý của mình.
Kevin Vermeer

1
Cả hai điểm rất công bằng. Ngay cả khi đi với số lượng phần thấp, pic32 không khác biệt về chi phí hoặc các thành phần bên ngoài so với điều này và nếu nó có 512K flash nội bộ, nó thậm chí còn thắng.
captncraig

Có vẻ như một giải pháp thực tế sẽ là sử dụng pic32 và viết một bộ tải khởi động để phản xạ lại từ thẻ sd. Tôi sẽ gặp khó khăn khi sử dụng lại các chức năng cả bộ tải khởi động và mã người dùng sẽ cần, nhưng miễn là tôi giữ nó trong flash boot 12k, nó sẽ cung cấp cho toàn bộ mã người dùng và họ có thể bao gồm bất kỳ thư viện nào họ muốn tại nguồn cấp độ.
captncraig
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.