diff --git a/README.md b/README.md index 676f511..ba2bca0 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ https://picocomputer.github.io/ -Requires Sphinx: +Built with Sphinx: https://www.sphinx-doc.org/ + +You can make small edits directly in the GitHub web interface. diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css new file mode 100644 index 0000000..2a924f1 --- /dev/null +++ b/docs/source/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/docs/source/_static/ria-w-sandwich.jpg b/docs/source/_static/ria-w-sandwich.jpg new file mode 100644 index 0000000..85b66d4 Binary files /dev/null and b/docs/source/_static/ria-w-sandwich.jpg differ diff --git a/docs/source/api.rst b/docs/source/api.rst deleted file mode 100644 index 9ca78c8..0000000 --- a/docs/source/api.rst +++ /dev/null @@ -1,461 +0,0 @@ -RP6502-API -########## - -Rumbledethumps Picocomputer 6502 Application Programming Interface. - -.. contents:: Table of Contents - :local: - -1. Introduction -=============== - -The :doc:`ria` runs a protected 32-bit kernel that you can call from the 6502. The kernel runs on a processor that is significantly faster than a 6502. This is the only practical way to run modern file systems, networking, and USB host stacks. - -The RP6502 presents an opportunity to create a new type of operating system. A 6502 OS based on the C programming language with familiar POSIX-like operations. - -2. Calling with fastcall -======================== - -The binary interface is based on fastcall from the `CC65 Internals `_. The RP6502 fastcall does not use or require anything from CC65 and is easy for assembly programmers to use. At its core, the API is based on a C ABI with three simple rules. - -* Stack arguments are pushed left to right. -* Last argument optionally passed by register A, AX, or AXSREG. -* Return value in register AX or AXSREG. - -A and X are the 6502 registers. The register AX combines them for 16 bits. AXSREG is 32 bits with the SREG bits in zero page. Let's look at how to make an OS call through the RIA registers. All kernel calls are specified as a C declaration like so: - -.. c:function:: int doit(int arg0, int arg1); - -The RIA has registers called RIA_A, RIA_X, and RIA_SREG. An int is 16 bits, so we set the RIA_A and RIA_X registers with arg1. I'll use "A" for the 6502 register and "RIA_A" for the RIA register in this explanation. - -We use the XSTACK for arg0. Reading or writing data to the RIA_XSTACK register removes or adds bytes to the XSTACK. It's a top-down stack, so push each argument from left to right and maintain little endian-ness in memory. - -To execute the call, store the operation ID in RIA_OP. The operation begins immediately. You can keep doing 6502 things, like running a loading animation, by polling RIA_BUSY. Or, JSR RIA_SPIN to block. - -The JSR RIA_SPIN method can unblock in less than 3 clock cycles and does an immediate load of A and X. Sequential operations will run fastest with this technique. Under the hood, you're jumping into a self-modifying program that runs on the RIA registers. - -.. code-block:: asm - - BRA #$?? ; RIA_BUSY {-2 or 0} - LDA #$?? ; RIA_A - LDX #$?? ; RIA_X - RTS - -Polling is simply snooping on the above program. The RIA_BUSY register is the -2 or 0 in the BRA above. The RIA datasheet specifies bit 7 indicates busy, which the 6502 can check quickly by using the BIT operator to set flag N. Once clear, we read RIA_A and RIA_X with absolute instructions. - -.. code-block:: asm - - wait: - BIT RIA_BUSY - BMI wait - LDA RIA_A - LDX RIA_X - -All operations returning RIA_A will also return RIA_X to assist with CC65's integer promotion requirements. RIA_SREG is only updated for 32-bit returns. RIA_ERRNO is only updated if there is an error. - -Some operations return data on the stack. You must pull the entire stack before the next call. However, tail call optimizations are possible. For example, you can chain read_xstack() and write_xstack() to copy a file without using any RAM or XRAM. - -2.1. Short Stacking -------------------- - -In the never ending pursuit of saving all the clocks, it is possible to save a few on the stack push if you don't need all the range. This only works on the stack argument that gets pushed first. For example: - -.. code-block:: C - - long lseek_impl(long offset, char whence, int fildes) - -Here we are asked for a 64 bit value. Not coincidentally, it's in the right position for short stacking. If, for example, you only need 24 bits, push only three bytes. The significant bytes will be implicit. - -2.2. Shorter Integers ---------------------- - -Many operations can save a few clocks by ignoring REG_X. All integers are always available as 16 bits to assist with CC65 and integer promotion. However, many operations will ignore REG_X on the register parameter and limit their return to fit in REG_A. This will be documented below as "A regs". - -2.3. Bulk Data --------------- - -Functions that move bulk data may come in two flavors. These are any function with a pointer parameter. This pointer is meaningless to the kernel because it can not change 6502 RAM. Instead, we use the XSTACK or XRAM for data buffers. - -2.3.1. Bulk XSTACK Operations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -These only work if the count is 512 or less. Bulk data is passed on the XSTACK, which is 512 bytes. A pointer appears in the C prototype to indicate the type and direction of this data. Let's look at some examples. - -.. code-block:: C - - int open(const char *path, int oflag); - -Send `oflag` in AX. Send the path on XSTACK by pushing the string starting with the last character. You may omit pushing the terminating zero, but strings are limited to a length of 255. Calling this from the C SDK will "just work" because there's an implementation that pushes the string for you. - -.. code-block:: C - - int read_xstack(void *buf, unsigned count, int fildes) - -Send `count` as a short stack and `fildes` in AX. The returned value in AX indicates how many values must be pulled from the stack. If you call this from the C SDK then it will copy XSTACK to buf[] for you. - -.. code-block:: C - - int write_xstack(const void *buf, unsigned count, int fildes) - -Send `fildes` in AX. Push the data to XSTACK. Do not send `count`, the kernel knows this from its internal stack pointer. If you call this from the C SDK then it will copy buf[] to XSTACK for you. - -Note that read() and write() are part of the C SDK, not a kernel operation. CC65 requires them to support more than 256 bytes, so they have wrapper logic to make multiple kernel calls when necessary. - -2.3.2. Bulk XRAM Operations -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -These load and save XRAM directly. You can load game assets without going through 6502 RAM or capture a screenshot with ease. - -.. code-block:: C - - int read_xram(xram_addr buf, unsigned count, int fildes) - int write_xram(xram_addr buf, unsigned count, int fildes) - -The kernel expects `buf` and `count` on the XSTACK as integers with `filedes` in AX. The buffer is effectively &XRAM[buf] here. There's nothing special about these calls in regards to how the binary interface rules are applied. They are interesting because of their high performance for loading assets. - -3. Function Reference -===================== - -Much of this API is based on CC65 and POSIX. In particular, filesystem access should feel extremely modern. However, some operations will have different argument orders or bitfield values than what you're used to. The reason for this becomes apparent when you start to work in assembly and fine tune short stacking and integer demotions. You might not notice the differences if you only work in C because the standard library has wrapper functions and familiar prototypes. For example, the lseek_impl() described below has reorderd arguments that are optimized for short stacking the long argument. But you never call lseek_impl() from C, you call the usual lseek() which has the traditional argument order. - -zxstack -------- -.. c:function:: void zxstack(void); - -Abandon the xstack by resetting the pointer. Not needed for normal operation. This is the only operation that doesn't require waiting for completion. - -xreg ----- - -.. c:function:: int xreg(char device, char channel, unsigned char address, ...); - -.. c:function:: int xregn(char device, char channel, unsigned char address, unsigned count, ...); - - The only difference is that xregn() requires a count of the variadic arguments. Using xreg() avoids making a counting error and is slightly smaller in CC65. - - Set extended registers on a PIX device. See the :doc:`ria` and :doc:`vga` documentation for what each register does. Setting extended registers can fail, which you should use for feature detection. EINVAL means the device responded with a negative acknowledgement. EIO means there was a timeout waiting for ack/nak. - - :param device: PIX device ID. 0-6 - :param channel: PIX channel. 0-15 - :param address: PIX address. 0-255 - :param ...: 16 bit integers to set starting at address. - :errno: EINVAL, EIO - - -phi2 ----- - -.. c:function:: int phi2(void) - - Retrieves the PHI2 setting from the RIA. Applications can use this for adjusting to or rejecting different clock speeds. - - :returns: The 6502 clock speed in kHz. Typically 750 <= x <= 8000. - :errno: will not fail - - -codepage --------- - -.. c:function:: int codepage(int cp) - - Temporarily overrides the code page if non zero. Returns to system setting when 6502 stops. This is the encoding the filesystem is using and, if VGA is installed, the console and default font. If zero, the system CP setting is selected and returned. If the requested code page is unavailable, a different code page will be selected and returned. For example: ``if (850!=codepage(850)) puts("error");`` - - :param cp: code page or 0 for system setting. - - :returns: The code page. One of: 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950. - :errno: will not fail - - -lrand ------ - -.. c:function:: long lrand(void) - - Generates a random number starting with entropy on the RIA. This is suitable for seeding a RNG or general use. The 16-bit rand() in the CC65 library can be seeded with this by calling its non-standard _randomize() function. - - :returns: Chaos. 0x0 <= x <= 0x7FFFFFFF - :errno: will not fail - - -stdin_opt ---------- - -.. c:function:: int stdin_opt(unsigned long ctrl_bits, unsigned char str_length) - - Additional options for the STDIN line editor. Set the str_length to your buffer size - 1 to make gets() safe. This can also guarantee no split lines when using fgets() on STDIN. - - :param ctrl_bits: Bitmap of ASCII 0-31 defines which CTRL characters can abort an input. When CTRL key is pressed, any typed input remains on the screen but the applicaion receives a line containing only the CTRL character. e.g. CTRL-C + newline. - :param str_length: 0-255 default 254. The input line editor won't allow user input greater than this length. - :a regs: return, str_length - :returns: 0 on success - :errno: will not fail - - -clock ------ - -.. c:function:: unsigned long clock(void) - - Obtain the value of a monotonic clock that updates 100 times per second. Wraps approximately every 497 days. - - :returns: 1/100 second monotonic clock - :errno: will not fail - - -clock_getres ------------- - -.. c:function:: int clock_getres(clockid_t clock_id, struct timespec *res) - - .. code-block:: c - - struct timespec { - uint32_t tv_sec; /* seconds */ - int32_t tv_nsec; /* nanoseconds */ - }; - - Copies the clock resolution to `res`. - - :param clock_id: 0 for CLOCK_REALTIME. - :returns: 0 on success. -1 on error. - :a regs: return, clock_id - :errno: EINVAL - - -clock_gettime -------------- - -.. c:function:: int clock_gettime(clockid_t clock_id, struct timespec *tp) - - Copies the current time to `tp`. - - :param clock_id: 0 for CLOCK_REALTIME. - :returns: 0 on success. -1 on error. - :a regs: return, clock_id - :errno: EINVAL, EUNKNOWN - - -clock_settime -------------- - -.. c:function:: int clock_settime(clockid_t clock_id, const struct timespec *tp) - - Sets the current time to `tp`. - - :param clock_id: 0 for CLOCK_REALTIME. - :returns: 0 on success. -1 on error. - :a regs: return, clock_id - :errno: EINVAL, EUNKNOWN - - -clock_gettimezone ------------------ - -.. c:function:: int clock_gettimezone(uint32_t time, clockid_t clock_id, struct _timezone *tz) - - .. code-block:: c - - struct _timezone - { - int8_t daylight; /* >0 if daylight savings time active */ - int32_t timezone; /* Number of seconds behind UTC */ - char tzname[5]; /* Name of timezone, e.g. CET */ - char dstname[5]; /* Name when daylight true, e.g. CEST */ - }; - - Populates a CC65 _timezone structure for the requested time. Use `help set tz` on the monitor to learn about configuring your time zone. - - :param time: time_t compatible integer. - :param clock_id: 0 for CLOCK_REALTIME. - :returns: 0 on success. -1 on error. - :a regs: return, clock_id - :errno: EINVAL - - -open ----- - -.. c:function:: int open(const char *path, int oflag) - - Create a connection between a file and a file descriptor. - - :param path: Pathname to a file. - :param oflag: Bitfield of options. - :returns: File descriptor. -1 on error. - :a regs: return, oflag - :errno: EINVAL, EMFILE, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, FR_INVALID_OBJECT, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES - :Options: - | O_RDONLY 0x01 - | Open for reading only. - | O_WRONLY 0x02 - | Open for writing only. - | O_RDWR 0x03 - | Open for reading and writing. - | O_CREAT 0x10 - | Create the file if it does not exist. - | O_TRUNC 0x20 - | Truncate the file length to 0 after opening. - | O_APPEND 0x40 - | Read/write pointer is set end of the file. - | O_EXCL 0x80 - | If O_CREAT and O_EXCL are set, fail if the file exists. - - -close ------ - -.. c:function:: int close(int fildes) - - Release the file descriptor. File descriptor will rejoin the pool available for use by open(). - - :param fildes: File descriptor from open(). - :returns: 0 on success. -1 on error. - :a regs: return, fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT - - -read ----- - -.. c:function:: int read(int fildes, void *buf, unsigned count) - - Read `count` bytes from a file to a buffer. - - :param buf: Destination for the returned data. - :param count: Quantity of bytes to read. 0x7FFF max. - :param fildes: File descriptor from open(). - :returns: On success, number of bytes read is returned. On error, -1 is returned. - :a regs: fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT - - -read_xstack ------------ - -.. c:function:: int read_xstack(void *buf, unsigned count, int fildes) - - Read `count` bytes from a file to xstack. - - :param buf: Destination for the returned data. - :param count: Quantity of bytes to read. 0x100 max. - :param fildes: File descriptor from open(). - :returns: On success, number of bytes read is returned. On error, -1 is returned. - :a regs: fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT - -read_xram ---------- - -.. c:function:: int read_xram(unsigned buf, unsigned count, int fildes) - - Read `count` bytes from a file to xram. - - :param buf: Destination for the returned data. - :param count: Quantity of bytes to read. 0x7FFF max. - :param fildes: File descriptor from open(). - :returns: On success, number of bytes read is returned. On error, -1 is returned. - :a regs: fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT - - -write ------ - -.. c:function:: int write(int fildes, const void *buf, unsigned count) - - Write `count` bytes from buffer to a file. - - :param buf: Location of the data. - :param count: Quantity of bytes to write. 0x7FFF max. - :param fildes: File descriptor from open(). - :returns: On success, number of bytes written is returned. On error, -1 is returned. - :a regs: fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT - - -write_xstack ------------- - -.. c:function:: int write_xstack(const void *buf, unsigned count, int fildes) - - Write `count` bytes from xstack to a file. - - :param buf: Location of the data. - :param count: Quantity of bytes to write. 0x100 max. - :param fildes: File descriptor from open(). - :returns: On success, number of bytes written is returned. On error, -1 is returned. - :a regs: fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT - - -write_xram ----------- - -.. c:function:: int write_xram(unsigned buf, unsigned count, int fildes) - - Write `count` bytes from xram to a file. - - :param buf: Location of the data. - :param count: Quantity of bytes to write. 0x7FFF max. - :param fildes: File descriptor from open(). - :returns: On success, number of bytes written is returned. On error, -1 is returned. - :a regs: fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT - - -lseek ------ - -.. c:function:: off_t lseek(int fildes, off_t offset, int whence) -.. c:function:: static long lseek_impl(long offset, char whence, int fildes) - - Move the read/write pointer. This is implemented internally with an argument order to take advantage of short stacking the offset. - - :param offset: How far you wish to seek. - :param whence: From whence you wish to seek. - :param fildes: File descriptor from open(). - :returns: Read/write position. -1 on error. If this value would be too large for a long, the returned value will be 0x7FFFFFFF. - :a regs: fildes - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT - :whence: - | SEEK_SET = 2 - | The start of the file plus offset bytes. - | SEEK_CUR = 0 - | The current location plus offset bytes. - | SEEK_END = 1 - | The size of the file plus offset bytes. - - -unlink ------- - -.. c:function:: int unlink (const char* name) - - Removes a file or directory from the volume. - - :param name: File or directory name to unlink (remove). - :returns: 0 on success. -1 on error. - :errno: FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE - - -rename ------- - -.. c:function:: int rename (const char* oldname, const char* newname) - - Renames and/or moves a file or directory. - - :param oldname: Existing file or directory name to rename. - :param newname: New object name. - :returns: 0 on success. -1 on error. - :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_EXIST, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE - - -exit ----- -.. c:function:: void exit(int status) - - Halt the 6502 and return to the kernel command interface. This is the only operation that does not return. RESB will be pulled down before the next instruction can execute. Status is currently ignored but will be used in the future. - - :param status: 0 is good, 1-255 for error. - :a regs: status diff --git a/docs/source/conf.py b/docs/source/conf.py index 3da1319..df9d0ff 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -6,10 +6,10 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = 'RP6502' -copyright = '2023 Rumbledethumps' +project = 'Picocomputer' +copyright = '2025 Rumbledethumps' author = 'Rumbledethumps' -release = '0.0-pre' +release = '' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -25,5 +25,11 @@ html_theme = 'alabaster' html_static_path = ['_static'] html_theme_options = { - 'font_family': 'Arial', + 'font_family': 'Arial, sans-serif', + 'github_banner': True, + 'github_user': 'picocomputer', + 'github_repo': '', + 'fixed_sidebar': True, + 'show_relbars': True, + 'sidebar_width': '230px', # undo alabaster's override } diff --git a/docs/source/hardware.rst b/docs/source/hardware.rst index ad5bda2..9c6d43d 100644 --- a/docs/source/hardware.rst +++ b/docs/source/hardware.rst @@ -1,93 +1,71 @@ -Schematic, PCB, and Parts -######################### - -Schematic ---------- - -`Picocomputer 6502 <_static/2023-06-07-rp6502.pdf>`_ (pdf) - - -Memory Map ----------- +======== +Hardware +======== +The Picocomputer 6502 is a homebrew computer you build yourself. You don't +need to understand the electronics, you don't need to solder, but you will +need to plug the eight ICs into their sockets. -There is no ROM. Nothing in zero page is used or reserved. There isn't a -book-sized list to study. The Picocomputer design lets you start with a clean -slate for every project. VGA, USB, and WiFi are all accessed using the 32 -registers of the RIA. +All parts are currently in production. The Raspberry Pi Pico 2 will +remain in production until at least `January 2040 +`_. +The hardware design has already survived the Pico 1 to Pico 2 transition. +The manufacturing lifetime of this project is expected to extend into a time +where hobbyist ASICs are democratized. -.. list-table:: - :widths: 25 75 - :header-rows: 1 - - * - Address - - Description - * - 0000-FEFF - - RAM, 63.75K - * - FF00-FFCF - - Unassigned - * - FFD0-FFDF - - VIA, see the `WDC datasheet `_ - * - FFE0-FFFF - - RIA, see the :doc:`RP6502 datasheet ` - * - 10000-1FFFF - - RAM, 64K for :doc:`RIA ` and :doc:`VGA ` - - -The unassigned space is available for hardware experimenters. You will need to -redesign the address decoder logic hardware to use this address space. It is -recommended that additional VIAs be added "down" and other hardware added -"up". For example: VIA0 at FFD0, VIA1 at FFC0, SID0 at FF00, and SID1 at -FF20. +Schematic +========= +`Picocomputer 6502 <_static/2023-06-07-rp6502.pdf>`_ (pdf) -I use "Picocomputer 6502" to refer to the reference design with the above -memory map. Please use a differentiating name if you change the hardware. For -example, "Picocomputer VERA" or "Ulf's Dream Computer". Think about what -people asking for help should call the device and go with that. Buying a Picocomputer ---------------------- +===================== -You will need to place two orders. First, for the Printed Circuit Board. -Second, for the electronic components. Some PCB factories will do the soldering -for you, but you'll still need to order the ICs and plug them into sockets. +You will need to place two orders. First, for the Printed Circuit Board (PCB). +Second, for the electronic components. Some PCB factories will do the +soldering for you, but you'll still need to order the ICs and plug them +into sockets. I have circuit boards in a `Tindie store -`_ that ships only to the United -States. International shipping is either too slow or too expensive when -compared to getting boards made locally or in China. +`_ that ships only to the +United States. International shipping is either too slow or too expensive +when compared to getting boards made locally or in China. -USA import tariffs are not an issue with this project. Only a few dollars of -resistors are made in China. Orders to my store and Mouser ship from the USA, -so you won't get a surprise bill from the courier. +USA import tariffs are not an issue with this project. Orders to my store +and Mouser ship from the USA, so you won't get a surprise bill from the +courier. Step 0. Read This ================= The debug header on the Pi Pico 2 W with headers doesn't fit any of the -existing cases. It's only useful for attaching a debugger to the kernel, -so just pull it off and get on with things. The Pi Picos you solder your +existing cases. It's only useful for attaching a debugger, +so just pull it off and get on with things. The Pi Picos where you solder your own headers to do not have this clearance issue. The boot message does not say COLOR anymore. Do not assume your device will behave exactly the same as an old YouTube video. -The three-pin debug connections under the RIA aren't used anymore. This is an -artifact of early development. +The three-pin debug connections under the RIA aren't used anymore. This is +an artifact of early development. Most VGA-to-HDMI cables can get power from the Picocomputer. Some will need external power applied. All are zero lag. + Step 1. Watch the Videos ======================== -To solder, or not to solder, that is the question. We're living in the future. -You can homebrew a 6502 without a soldering iron. Choose your path: +To solder, or not to solder, that is the question. We're living in the +future. You can homebrew a 6502 without a soldering iron. Choose your path: + +`Here's the video where I build one without soldering. +`_ -`Here's the video where I build one without soldering. `_ +`Here's the video where I solder one myself. +`_ -`Here's the video where I solder one myself. `_ Step 2. Order Printed Circuit Boards ==================================== @@ -109,13 +87,14 @@ you a classic green and white board with lead (Pb) HASL. Consider getting the lead-free HASL upgrade if the other four boards will be kicking around a drawer for the next 20 years. + Step 3. Order Assembly ====================== Skip this step if you want to solder it yourself. -PCBWay has a minimum quantity of one for assembly. They will use the boards you -ordered in step 2. What you'll have them make is a "board of sockets" - the +PCBWay has a minimum quantity of one for assembly. They will use the boards +you ordered in step 2. What you'll have them make is a "board of sockets" - the ICs will be installed by you later. It should never be constrained on parts availability since there are multiple vendors for every part. @@ -126,15 +105,17 @@ Request assembly with your PCB order and send the `BOM, notes, and photos are no surface mount parts. The default options will work. Let them source the parts. Let them make substitutions. -There will be a short delay as they get you a price for the bill-of-materials. -Then you can pay and wait. I was estimated four weeks and got it in three. +There will be a short delay as they get you a price for the +bill-of-materials. Then you can pay and wait. I was estimated four weeks and +got it in three. If they have a question, make sure both you and your sales rep read the notes -you sent them. If you have a question about options on their web site, ask -your sales rep before asking on the forums. They help people all day long with +you sent them. If you have a question about options on their web site, ask your +sales rep before asking on the forums. They help people all day long with projects far more complex than this. Even if you don't understand what you are -doing, they can figure it out by looking at the zip files. Really, they do -this all day long, and will probably enjoy the easy win. +doing, they can figure it out by looking at the zip files. Really, they do this +all day long, and will probably enjoy the easy win. + Step 4. More Parts ================== @@ -144,33 +125,38 @@ Factory assembled boards will need the eight ICs added to them. Upload the `_ shopping cart. If you are soldering it yourself, upload the `full parts list -<_static/rp6502-reva-full.csv>`_ to a Mouser_ shopping -cart. +<_static/rp6502-reva-full.csv>`_ to a Mouser_ shopping cart. + +Mouser will print the Customer# on each of the parts bags. Assign this +column to the CSV reference column to get your bags labelled like "C1-C9, C11" +etc. If you forget, no problem becuase the PCB silkscreen has location info. + +If something is out of stock, consult the substitution notes below. -If something is out of stock, consult the substitution notes below. If it's the -Pi Pico or Pi Pico H, do a text search since marketplace vendors often have -them. Step 5. Pi Pico Firmware ========================= -Download the `UF2 files `_. +Download the `UF2 files +`_. + +To load firmware on a Pi Pico 2, hold its BOOTSEL button down while plugging it +into a computer. The Pi Pico 2 will appear as a storage device. Copy the RIA UF2 +file to make a :doc:`ria_w` and the VGA UF2 file to make a :doc:`vga`. It should +take less than 30 seconds to copy. The LED turns on when done. -To load firmware on a Pi Pico, hold its BOOTSEL button down while plugging it -into a computer. The Pi Pico will appear as a storage device. Copy the VGA UF2 -file to make a Pico VGA and the RIA UF2 file to make a Pico RIA. It should take -less than 30 seconds to copy. The LED turns on when done. Acrylic Sandwich Case ---------------------- +===================== The circuit board is 150 x 100mm (4x6 inches). I regularly see vendors on Amazon and eBay selling 150 x 100 x 3mm acrylic sheets. You'll need to drill 3mm holes for M3 standoffs. The recommended standoff height is >=16mm for the top and >=3.5mm for the bottom. + Full Parts List (All Components) --------------------------------- +================================= `All Parts CSV <_static/rp6502-reva-full.csv>`_ @@ -179,9 +165,8 @@ Full Parts List (All Components) :header-rows: 1 - Active Parts List (ICs Only) ----------------------------- +============================= `Active Parts CSV <_static/rp6502-reva-active.csv>`_ @@ -189,8 +174,9 @@ Active Parts List (ICs Only) :file: _static/rp6502-reva-active.csv :header-rows: 1 + Pi Picos Parts List -------------------- +=================== Alternative part numbers for the Pi Picos. @@ -200,7 +186,7 @@ Alternative part numbers for the Pi Picos. Parts Substitution ------------------- +=================== All resistors are <= 1% tolerance. Any power rating. Leads must fit 0.8mm plated holes spaced 10mm apart. Recommended size is approximately 0.1" x 0.25" @@ -238,7 +224,7 @@ The WDC W65C02S and W65C22S must not be substituted. Do not attempt to use NMOS chips (without the C in the number). Some older CMOS designs may work but there are no plans to support out-of-production ICs. -Only the Raspberry Pi design of the Pi Pico has been tested. Both original and -"H" (header) versions work great. Pin-compatible alternatives may work, check +Only the Raspberry Pi design of the Pi Pico 2 has been tested. Both original and +"H" (header) versions work great. Pin-compatible alternatives usually work, check the forums. The 3-pin SWD connection on the Pi Pico RIA is no longer used and may be ignored when looking for alternatives. diff --git a/docs/source/index.rst b/docs/source/index.rst index 7fb5b66..3f93883 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,57 +2,80 @@ :hidden: Hardware - RIA - RIA W - VGA - API + RP6502-RIA + RP6502-RIA-W + RP6502-VGA + RP6502-OS -Picocomputer 6502 -================= +============ +Picocomputer +============ -The **Picocomputer 6502** is a platform for exploring retro computing and game development, bridging the gap between authentic 8-bit hardware and modern devices. +The **Picocomputer 6502** is a tribute to the processor that launched a +computing revolution. The lack of apparent complexity is a by product of +the design philosophy: Keep the essence of programming a 6502 and 6522 +then rethink everything else. -.. image:: _static/founders.jpg +.. image:: _static/ria-w-sandwich.jpg :width: 600 :alt: Picocomputer Photo + Key Features ------------- +============ - **64KB System RAM** - **64KB Extended RAM** -- **VGA Graphics Output** +- **VGA and HD Output** - **8-Channel Stereo Sound Generator** -- **USB Support** for Keyboard, Mouse, and Gamepads -- **WiFi** for NTP and modem emulation -- **100% Through-Hole Construction** +- **Protected Operating System** +- **USB** for Keyboard, Mouse, and Gamepads +- **Bluetooth LE** for Keyboard, Mouse, and Gamepads +- **WiFi** modem emulation +- **Real Time Clock** with DST and NTP + Resources ---------- +========= -For support and community interaction, please use the following channels: +For support and community interaction, use the following channels: - **GitHub:** https://github.com/picocomputer - **Forums:** https://github.com/picocomputer/community/discussions - **Discord:** https://discord.gg/TC6X8kTr6d - **Wiki:** https://github.com/picocomputer/community/wiki -- **YouTube:** https://youtube.com/playlist?list=PLvCRDUYedILfHDoD57Yj8BAXNmNJLVM2r -Datasheets & Documentation --------------------------- +The entire development process was documented in a series of YouTube videos. +The broad strokes are all still in place but remember that these video were +made during development. + +- **YouTube:** + https://youtube.com/playlist?list=PLvCRDUYedILfHDoD57Yj8BAXNmNJLVM2r + + +How To Obtain +============= + +The **Picocomputer 6502** is a single board computer you build yourself. It has +been built by hundreds of people. You can also have a single unit manufactured +especially for you in China. The whole process is documented and well tested. + +- :doc:`hardware`: Schematic and manufacturing information. -The RP6502 chipset consists of three main components: -- :doc:`RP6502-RIA`: An interface adapter for the 6502, similar to CIA, VIA, and ACIA devices. -- :doc:`RP6502-RIA-W`: An alternative RIA with wireless radio technology. -- :doc:`RP6502-VGA`: An optional video chip that connects to the RP6502-RIA. +Datasheets +========== -All components are based on Raspberry Pi Pico 2 boards running RP6502 firmware. +The **Picocomputer 6502** is a reference design for RP6502 modular hardware. +The only required module is a RP6502-RIA. -Further documentation: +- :doc:`ria`: Interface adapter for the 6502, akin to CIA, + VIA, and ACIA devices. +- :doc:`ria_w`: Wireless features available when using the + recommended "Pico 2 W". +- :doc:`vga`: Optional video adapter that connects to the + RP6502-RIA. +- :doc:`os`: The operating system and application programming interface. -- :doc:`Schematic, PCB, and Parts ` -- :doc:`RIA Interface Adapter ` -- :doc:`RIA W Interface Adapter ` -- :doc:`VGA Graphics Processing Unit ` -- :doc:`API for 6502 Programming ` +`Please contribute to this documentation. +`_ diff --git a/docs/source/os.rst b/docs/source/os.rst new file mode 100644 index 0000000..7fadb52 --- /dev/null +++ b/docs/source/os.rst @@ -0,0 +1,1256 @@ +============================ +RP6502-OS +============================ + +RP6502 - Operating System + + +Introduction +============ + +The :doc:`ria` runs a 32-bit protected operating system that +you can call from the 6502. The :doc:`os` does not use any 6502 system RAM +and will not interfere with developing a native 6502 OS. + +The :doc:`os` is loosely based on POSIX with an Application Binary +Interface (ABI) similar to `cc65's fastcall +`__. +It provides stdio.h and unistd.h services to both `cc65 +`__ and `llvm-mos `_ +compilers. There are also calls to access RP6502 features and manage +FAT32 filesystems. ExFAT is ready to go and will be enabled when the +patents expire. + + +Memory Map +========== + +There is no ROM. Nothing in zero page is used or reserved. The +Picocomputer starts as a clean slate for every project. VGA, audio, +storage, keyboards, mice, gamepads, RTC, and networking are all accessed +using only the 32 registers of the RIA. + +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - Address + - Description + * - $0000-$FEFF + - RAM, 63.75K + * - $FF00-$FFCF + - Unassigned + * - $FFD0-$FFDF + - VIA, see the `WDC datasheet + `_ + * - $FFE0-$FFFF + - RIA, see the :doc:`RP6502-RIA datasheet ` + * - $10000-$1FFFF + - XRAM, 64K for :doc:`ria` and :doc:`vga` + +The unassigned space is available for hardware experimenters. You will +need to design your own chip select hardware to use this +address space. It is recommended that additional VIAs be added "down" +and other hardware added "up". For example: VIA0 at $FFD0, VIA1 at +$FFC0, SID0 at $FF00, and SID1 at $FF20. + + +Application Binary Interface +============================ + +The ABI for calling the operating system is based on +fastcall from the `cc65 internals +`__. The :doc:`os` +does not use or require anything from cc65 and is easy for +assembly programmers to use. At its core, the OS ABI is four simple rules. + +* Stack arguments are pushed left to right. +* Last argument passed by register A, AX, or AXSREG. +* Return value in register AX or AXSREG. +* May return data on the stack. + +A and X are the 6502 registers. The pseudo register AX combines them for +16 bits. AXSREG allows 32 bits with the 16 additional SREG bits. Let's +look at how to make an OS call through the RIA registers. All OS calls +are specified as a C declaration like so: + +.. c:function:: int doit(int arg0, int arg1); + +The RIA has registers called RIA_A, RIA_X, and RIA_SREG. An int is 16 +bits, so we set the RIA_A and RIA_X registers with arg1. I'll use "A" +for the 6502 register and "RIA_A" for the RIA register in this +explanation. + +We use the XSTACK for arg0. Reading or writing data to the +RIA_XSTACK register removes or adds bytes to the XSTACK. It's a +top-down stack, so push each argument from left to right and maintain +little endian-ness in memory. + +To execute the call, store the operation ID in RIA_OP. The operation +begins immediately. You can keep doing 6502 things, like running a +loading animation, by polling RIA_BUSY. Or, JSR RIA_SPIN to block. + +The JSR RIA_SPIN method can unblock in less than 3 clock cycles and +does an immediate load of A and X. Sequential operations will run +fastest with this technique. Under the hood, you're jumping into a +self-modifying program that runs on the RIA registers. + +.. code-block:: asm + + BRA #$?? ; RIA_BUSY {-2 or 0} + LDA #$?? ; RIA_A + LDX #$?? ; RIA_X + RTS + +Polling is simply snooping on the above program. The RIA_BUSY register +is the -2 or 0 in the BRA above. The RIA datasheet specifies bit 7 +indicates busy, which the 6502 can check quickly by using the BIT +operator to set flag N. Once clear, we read RIA_A and RIA_X with +absolute instructions. + +.. code-block:: asm + + wait: + BIT RIA_BUSY + BMI wait + LDA RIA_A + LDX RIA_X + +All operations returning RIA_A will also return RIA_X to assist with +C integer promotion. RIA_SREG is only updated for +32-bit returns. RIA_ERRNO is only updated if there is an error. + +Some operations return strings or structures on the stack. You must +pull the entire stack before the next call. However, tail call +optimizations are possible. For example, you can chain read_xstack() +and write_xstack() to copy a file without using any RAM or XRAM. + +Short Stacking +--------------- + +In the never ending pursuit of saving all the cycles, it is possible to +save a few on the stack push if you don't need all the range. This only +works on the stack argument that gets pushed first. For example: + +.. code-block:: C + + long f_lseek(long offset, char whence, int fildes) + +Here we need to push a 32 bit value. Not coincidentally, it's in the +right position for short stacking. If, for example, the offset always +fits in 16 bits, push only two bytes instead of four. + +Shorter AX +---------- + +Many operations can save a few cycles by ignoring REG_X. All returned +integers are always available as at least 16 bits to assist with C +integer promotion. However, many operations will ignore REG_X in the +register parameter and limit their return to fit in REG_A. These will be +documented below as "A regs". + +Bulk Data +--------- + +Functions that move bulk data may come in two flavors. These are any +function with a mutable pointer parameter. A RAM pointer is meaningless +to the RIA because it can not change 6502 RAM. Instead, we use the +XSTACK or XRAM to move data. + +Bulk XSTACK Operations +~~~~~~~~~~~~~~~~~~~~~~ + +These only work if the size is 512 bytes or less. Bulk data is passed on +the XSTACK, which is 512 bytes. A pointer appears in the C prototype to +indicate the type and direction of this data. Let's look at some +examples. + +.. code-block:: C + + int open(const char *path, int oflag); + +Send `oflag` in RIA_A. RIA_X doesn't need to be set according the to +docs below. Send the path on XSTACK by pushing the string starting with +the last character. You may omit pushing the terminating zero, but +strings are limited to a length of 255. Calling this from the C SDK will +"just work" because there's an implementation that pushes the string for +you. + +.. code-block:: C + + int read_xstack(void *buf, unsigned count, int fildes) + +Send `count` as a short stack and `fildes` in RIA_A. RIA_X doesn't need +to be set according the to docs below. The returned value in AX +indicates how many values must be pulled from the stack. If you call +this from the C SDK then it will copy XSTACK to buf[] for you. + +.. code-block:: C + + int write_xstack(const void *buf, unsigned count, int fildes) + +Send `fildes` in RIA_A. RIA_X doesn't need to be set according the to +docs below. Push the buf data to XSTACK. Do not send `count`, the OS +knows this from its internal stack pointer. If you call this from the C +SDK then it will copy count bytes of buf[] to XSTACK for you. + +Note that read() and write() are part of the C SDK, not an OS +operation. C requires these to support a count larger than the XSTACK +can return so the implementation makes multiple OS calls as necessary. + +Bulk XRAM Operations +~~~~~~~~~~~~~~~~~~~~ + +These load and save XRAM directly. You can load game assets without +going through 6502 RAM or capture a screenshot with ease. + +.. code-block:: C + + int read_xram(xram_addr buf, unsigned count, int fildes) + int write_xram(xram_addr buf, unsigned count, int fildes) + +The OS expects `buf` and `count` on the XSTACK as integers with +`filedes` in RIA_A. The :doc:`os` has direct access to XRAM so +internally it will use something like &XRAM[buf]. You will need to use +RIA_RW0 or RIA_RW1 to access this memory from the 6502. + +These operations are interesting because of their high performance and +ability to work in the background while the 6502 is doing something +else. You can expect close to 64KB/sec, which means loading a game +level's worth of assets will take less than a second. + +Bulk XRAM operations are why the Picocomputer 6502 was designed +without paged memory. + + +Application Programmer Interface +================================ + +Much of this API is based on POSIX and FatFs. In particular, filesystem +and console access should feel extremely familiar. However, some +operations will have a different argument order or data structures than +what you're used to. The reason for this becomes apparent when you start +to work in assembly and fine tune short stacking and integer demotions. +You might not notice the differences if you only work in C because the +standard library has wrapper functions and familiar prototypes. For +example, the f_lseek() described below has reordered arguments that are +optimized for short stacking the long argument. But you don't have to +call f_lseek() from C, you can call the usual lseek() which has the +traditional argument order. + +The :doc:`os` is built around FAT filesystems, which is the defacto +standard for unsecured USB storage devices. POSIX filesystems are not +fully compatible with FAT but there is a solid intersection of basic IO +that is 100% compatible. You will see some familiar POSIX functions like +open() and others like f_stat() which are similar to the POSIX function +but tailored to FAT. Should it ever become necessary to have a POSIX +stat(), it can be implemented in the C standard library or in an +application by translating f_stat() data. + +ZXSTACK +------- +.. c:function:: void zxstack (void); + + | + + Abandon the xstack by resetting the xstack pointer. This is the only + operation that doesn't require waiting for completion. You do not need + to call this for failed operations. It can be useful if you want to + quickly ignore part of a returned structure. + + :Op code: RIA_OP_ZXSTACK 0x00 + :C proto: rp6502.h + +XREG +---- + +.. c:function:: int xreg (char device, char channel, unsigned char address, ...); +.. c:function:: int xregn (char device, char channel, unsigned char address, unsigned count, ...); + + | + + Using xreg() from C is preferred to avoid making a counting error. + Count doesn't need to be sent in the ABI so both prototypes are correct. + + The variadic argument is a list of ints to be stored in extended registers + starting at address on the specified device and channel. + See the :doc:`ria` and + :doc:`vga` documentation for what each register does. Setting + extended registers can fail, which you can use for feature + detection. EINVAL means the device responded with a negative + acknowledgement. EIO means there was a timeout waiting for ack/nak. + + This is how you add virtual hardware to extended RAM. Both the :doc:`ria` and + :doc:`vga` have a selection of virtual devices you can install. You can also + make your own hardware for the PIX bus and configure it with this call. + + :Op code: RIA_OP_XREG 0x01 + :C proto: rp6502.h + :param device: PIX device ID. 0:RIA, 1:VGA, 2-6:unassigned + :param channel: PIX channel. 0-15 + :param address: PIX address. 0-255 + :param ...: 16 bit integers to set starting at address. + :a regs: return + :errno: EINVAL, EIO + + +PHI2 +---- + +.. c:function:: int phi2 (void) + + | + + Retrieves the PHI2 setting from the RIA. Applications can use this + for adjusting to or rejecting different clock speeds. + + :Op code: RIA_OP_PHI2 0x02 + :C proto: rp6502.h + :returns: The 6502 clock speed in kHz. Typically 800 <= x <= 8000. + :errno: will not fail + + +CODE_PAGE +--------- + +.. c:function:: int code_page (int cp) + + | + + Temporarily overrides the code page if non zero. Returns to system + setting when 6502 stops. This is the encoding the filesystem is using + and, if VGA is installed, the console and default font. If zero, the + system CP setting is selected and returned. If the requested code + page is unavailable, a different code page will be selected and + returned. For example: ``if (850!=code_page(850)) puts("error");`` + + :Op code: RIA_OP_CODE_PAGE 0x03 + :C proto: rp6502.h + :param cp: code page or 0 for system setting. + :returns: The code page. One of: 437, 720, 737, 771, 775, 850, 852, + 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, + 950. + :errno: will not fail + + +LRAND +----- + +.. c:function:: long lrand (void) + + | + + Generates a random number starting with entropy on the RIA. This is + suitable for seeding a RNG or general use. The 16-bit rand() in the + cc65 library can be seeded with this by calling its non-standard + _randomize() function. + + :Op code: RIA_OP_LRAND 0x04 + :C proto: rp6502.h + :returns: Chaos. 0x0 <= x <= 0x7FFFFFFF + :errno: will not fail + + +STDIN_OPT +--------- + +.. c:function:: int stdin_opt (unsigned long ctrl_bits, unsigned char str_length) + + | + + Additional options for the STDIN line editor. Set the str_length to + your buffer size - 1 to make gets() safe. This can also guarantee no + split lines when using fgets() on STDIN. + + *** Experimental *** Likely to be replaced with stty-like something. Drop your + thoughts on the forums if you have specific needs. + + :Op code: RIA_OP_STDIN_OPT 0x05 + :C proto: rp6502.h + :param ctrl_bits: Bitmap of ASCII 0-31 defines which CTRL characters + can abort an input. When CTRL key is pressed, any typed input + remains on the screen but the applicaion receives a line containing + only the CTRL character. e.g. CTRL-C + newline. + :param str_length: 0-255 default 254. The input line editor won't + allow user input greater than this length. + :a regs: return, str_length + :returns: 0 on success + :errno: will not fail + + +ERRNO_OPT +--------- + +.. c:function:: int errno_opt (char option) + + | + + :doc:`os` calls will set RIA_ERRNO when an error occurs. This is used to + select which set of values to use because the compiler + libraries each use different constants in errno.h. Both cc65 + and llvm-mos call this automatically in the C runtime. The RIA_ERRNO value will not + change until it is set. Note that the C `errno` maps directly to RIA_ERRNO. + + :doc:`os` will map FatFs errors onto errno. RP6502 emulation and simulation + software is expected to map their native errors as well. The table below + shows the FatFs mappings. Because FatFs is so integral to the OS, + calls are documented here with their native FatFs errors to assist when + cross referencing the `FatFs documentation `__. + + :Op code: RIA_OP_ERRNO_OPT 0x06 + :C proto: None + :param option: One of the values from the table below. + :a regs: return, option + :returns: 0 on success + :errno: EINVAL + + .. list-table:: + :header-rows: 1 + :widths: 25 25 25 25 + + * - + - cc65 + - llvm_mos + - FatFs + * - option + - 1 + - 2 + - + * - ENOENT + - 1 + - 2 + - FR_NO_FILE, FR_NO_PATH + * - ENOMEM + - 2 + - 12 + - FR_NOT_ENOUGH_CORE + * - EACCES + - 3 + - 23 + - FR_DENIED, FR_WRITE_PROTECTED + * - ENODEV + - 4 + - 19 + - FR_NOT_READY, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM + * - EMFILE + - 5 + - 24 + - FR_TOO_MANY_OPEN_FILES + * - EBUSY + - 6 + - 16 + - FR_LOCKED + * - EINVAL + - 7 + - 22 + - FR_INVALID_NAME, FR_INVALID_PARAMETER + * - ENOSPC + - 8 + - 28 + - + * - EEXIST + - 9 + - 17 + - FR_EXIST + * - EAGAIN + - 10 + - 11 + - FR_TIMEOUT + * - EIO + - 11 + - 5 + - FR_DISK_ERR, FR_INT_ERR, FR_MKFS_ABORTED + * - EINTR + - 12 + - 4 + - + * - ENOSYS + - 13 + - 38 + - + * - ESPIPE + - 14 + - 29 + - + * - ERANGE + - 15 + - 34 + - + * - EBADF + - 16 + - 9 + - FR_INVALID_OBJECT + * - ENOEXEC + - 17 + - 8 + - + * - EDOM + - 18 + - 33 + - + * - EILSEQ + - 18 + - 84 + - + * - EUNKNOWN + - 18 + - 85 + - + +CLOCK +----- + +.. c:function:: unsigned long clock (void) + + | + + Obtain the value of a monotonic clock that updates 100 times per + second. Wraps approximately every 497 days. + + :Op code: RIA_OP_CLOCK 0x0F + :C proto: time.h + :returns: 1/100 second monotonic clock + :errno: will not fail + + +CLOCK_GETRES +------------ + +.. c:function:: int clock_getres (clockid_t clock_id, struct timespec *res) + + | + + .. code-block:: c + + struct timespec { + uint32_t tv_sec; /* seconds */ + int32_t tv_nsec; /* nanoseconds */ + }; + + Obtains the clock resolution. + + :Op code: RIA_OP_CLOCK_GETRES 0x10 + :C proto: time.h + :param clock_id: 0 for CLOCK_REALTIME. + :returns: 0 on success. -1 on error. + :a regs: return, clock_id + :errno: EINVAL + + +CLOCK_GETTIME +------------- + +.. c:function:: int clock_gettime (clockid_t clock_id, struct timespec *tp) + + | + + Obtains the current time. + + :Op code: RIA_OP_CLOCK_GETTIME 0x11 + :C proto: time.h + :param clock_id: 0 for CLOCK_REALTIME. + :returns: 0 on success. -1 on error. + :a regs: return, clock_id + :errno: EINVAL, EUNKNOWN + + +CLOCK_SETTIME +------------- + +.. c:function:: int clock_settime (clockid_t clock_id, const struct timespec *tp) + + | + + Sets the current time. + + :Op code: RIA_OP_CLOCK_SETTIME 0x12 + :C proto: time.h + :param clock_id: 0 for CLOCK_REALTIME. + :returns: 0 on success. -1 on error. + :a regs: return, clock_id + :errno: EINVAL, EUNKNOWN + + +CLOCK_GETTIMEZONE +----------------- + +.. c:function:: int clock_gettimezone (uint32_t time, clockid_t clock_id, struct _timezone *tz) + + .. code-block:: c + + struct _timezone + { + int8_t daylight; /* >0 if daylight savings time active */ + int32_t timezone; /* Number of seconds behind UTC */ + char tzname[5]; /* Name of timezone, e.g. CET */ + char dstname[5]; /* Name when daylight true, e.g. CEST */ + }; + + Returns a cc65 _timezone structure for the requested time. Use + `help set tz` on the monitor to learn about configuring your time + zone. + + *** Experimental *** time zones in cc65 are incomplete probably because + no other 6502 OS supports them. + + :Op code: RIA_OP_CLOCK_GETTIMEZONE 0x13 + :C proto: None, Experimental + :param time: time_t compatible integer. + :param clock_id: 0 for CLOCK_REALTIME. + :returns: 0 on success. -1 on error. + :a regs: return, clock_id + :errno: EINVAL + + +OPEN +---- + +.. c:function:: int open (const char *path, int oflag) + + | + + Create a connection between a file and a file descriptor. Up to 8 + files may be open at once. + + :Op code: RIA_OP_OPEN 0x14 + :C proto: fcntl.h + :param path: Pathname to a file. + :param oflag: Bitfield of options. + :returns: File descriptor. -1 on error. + :a regs: return, oflag + :errno: EINVAL, EMFILE, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, + FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, + FR_INVALID_OBJECT, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, + FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, + FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES + :Options: + + | O_RDONLY 0x01 + | Open for reading only. + | O_WRONLY 0x02 + | Open for writing only. + | O_RDWR 0x03 + | Open for reading and writing. + | O_CREAT 0x10 + | Create the file if it does not exist. + | O_TRUNC 0x20 + | Truncate the file length to 0 after opening. + | O_APPEND 0x40 + | Read/write pointer is set end of the file. + | O_EXCL 0x80 + | If O_CREAT and O_EXCL are set, fail if the file exists. + + +CLOSE +----- + +.. c:function:: int close (int fildes) + + | + + Finish pending writes and release the file descriptor. File descriptor + will rejoin the pool available for use by open(). + + :Op code: RIA_OP_CLOSE 0x15 + :C proto: fcntl.h + :param fildes: File descriptor from open(). + :returns: 0 on success. -1 on error. + :a regs: return, fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, + FR_TIMEOUT + + +READ +---- + +.. c:function:: int read (int fildes, void *buf, unsigned count) + + | + + Read `count` bytes from a file to a buffer. This is implemented in + the compiler library as a series of calls to read_xstack(). + + :Op code: None + :C proto: unistd.h + :param buf: Destination for the returned data. + :param count: Quantity of bytes to read. 0x7FFF max. + :param fildes: File descriptor from open(). + :returns: On success, number of bytes read is returned. On error, -1 + is returned. + :a regs: fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, + FR_INVALID_OBJECT, FR_TIMEOUT + + +READ_XSTACK +----------- + +.. c:function:: int read_xstack (void *buf, unsigned count, int fildes) + + | + + Read `count` bytes from a file to xstack. + + :Op code: RIA_OP_READ_XSTACK 0x16 + :C proto: rp6502.h + :param buf: Destination for the returned data. + :param count: Quantity of bytes to read. 0x100 max. + :param fildes: File descriptor from open(). + :returns: On success, number of bytes read is returned. On error, -1 + is returned. + :a regs: fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, + FR_INVALID_OBJECT, FR_TIMEOUT + +READ_XRAM +--------- + +.. c:function:: int read_xram (unsigned buf, unsigned count, int fildes) + + | + + Read `count` bytes from a file to xram. + + :Op code: RIA_OP_READ_XRAM 0x17 + :C proto: rp6502.h + :param buf: Destination for the returned data. + :param count: Quantity of bytes to read. 0x7FFF max. + :param fildes: File descriptor from open(). + :returns: On success, number of bytes read is returned. On error, -1 + is returned. + :a regs: fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, + FR_INVALID_OBJECT, FR_TIMEOUT + + +WRITE +----- + +.. c:function:: int write (int fildes, const void *buf, unsigned count) + + | + + Write `count` bytes from buffer to a file. This is implemented in + the compiler library as a series of calls to write_xstack(). + + :Op code: None + :C proto: unistd.h + :param buf: Location of the data. + :param count: Quantity of bytes to write. 0x7FFF max. + :param fildes: File descriptor from open(). + :returns: On success, number of bytes written is returned. On error, + -1 is returned. + :a regs: fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, + FR_INVALID_OBJECT, FR_TIMEOUT + + +WRITE_XSTACK +------------ + +.. c:function:: int write_xstack (const void *buf, unsigned count, int fildes) + + | + + Write `count` bytes from xstack to a file. + + :Op code: RIA_OP_WRITE_XSTACK 0x18 + :C proto: rp6502.h + :param buf: Location of the data. + :param count: Quantity of bytes to write. 0x100 max. + :param fildes: File descriptor from open(). + :returns: On success, number of bytes written is returned. On error, + -1 is returned. + :a regs: fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, + FR_INVALID_OBJECT, FR_TIMEOUT + + +WRITE_XRAM +---------- + +.. c:function:: int write_xram (unsigned buf, unsigned count, int fildes) + + | + + Write `count` bytes from xram to a file. + + :Op code: RIA_OP_WRITE_XRAM 0x19 + :C proto: rp6502.h + :param buf: Location of the data. + :param count: Quantity of bytes to write. 0x7FFF max. + :param fildes: File descriptor from open(). + :returns: On success, number of bytes written is returned. On error, + -1 is returned. + :a regs: fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, + FR_INVALID_OBJECT, FR_TIMEOUT + + +LSEEK +----- + +.. c:function:: static long f_lseek (long offset, char whence, int fildes) +.. c:function:: off_t lseek (int fildes, off_t offset, int whence) + + | + + Move the read/write pointer. The OS uses the ABI format of f_seek(). + An lseek() compatible wrapper is provided with the compiler library. + + This can also be used to obtain the current read/write position + with ``f_lseek(0, SEEK_CUR, fd)``. + + :Op code: See table below. + :C proto: f_lseek: rp6502.h, lseek: unistd.h + :param offset: How far you wish to seek. + :param whence: From whence you wish to seek. See table below. + :param fildes: File descriptor from open(). + :returns: Read/write position. -1 on error. If this value would be too + large for a long, the returned value will be 0x7FFFFFFF. + :a regs: fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, + FR_TIMEOUT + + .. list-table:: + :header-rows: 1 + :widths: 25 25 25 + + * - + - RIA_OP_LSEEK_LLVM + - RIA_OP_LSEEK_CC65 + * - RIA_OP_LSEEK + - 0x1D + - 0x1A + * - SEEK_SET + - 0 + - 2 + * - SEEK_CUR + - 1 + - 0 + * - SEEK_END + - 2 + - 1 + + +UNLINK +------ + +.. c:function:: int unlink (const char* name) + + | + + Removes a file or directory from the volume. + + :Op code: RIA_OP_UNLINK 0x1B + :C proto: unistd.h + :param name: File or directory name to unlink (remove). + :returns: 0 on success. -1 on error. + :errno: FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, + FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_WRITE_PROTECTED, + FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, + FR_LOCKED, FR_NOT_ENOUGH_CORE + + +RENAME +------ + +.. c:function:: int rename (const char* oldname, const char* newname) + + | + + Renames and/or moves a file or directory. + + :Op code: RIA_OP_RENAME 0x1C + :C proto: stdio.h + :param oldname: Existing file or directory name to rename. + :param newname: New object name. + :returns: 0 on success. -1 on error. + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, + FR_NO_PATH, FR_INVALID_NAME, FR_EXIST, FR_WRITE_PROTECTED, + FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, + FR_LOCKED, FR_NOT_ENOUGH_CORE + + +SYNCFS +------ + +.. c:function:: int syncfs (int fildes) + + | + + Finish pending writes for the file descriptor. + + :Op code: RIA_OP_SYNCFS 0x1E + :C proto: unistd.h + :param fildes: File descriptor from open(). + :returns: 0 on success. -1 on error. + :a regs: return, fildes + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, + FR_TIMEOUT + + +STAT +---- + +.. c:function:: int f_stat (const char* path, f_stat_t* dirent) + + .. code-block:: c + + typedef struct { + unsigned long fsize; + unsigned fdate; + unsigned ftime; + unsigned crdate; + unsigned crtime; + unsigned char fattrib; + char altname[12 + 1]; + char fname[255 + 1]; + } f_stat_t; + + Returns file or directory info for requested path. + See the `FatFs documentation `__ + for details about the data structure. + + :Op code: RIA_OP_STAT 0x1F + :C proto: rp6502.h + :param path: Pathname to a directory entry. + :param dirent: Returned f_stat_t data. + :returns: 0 on success. -1 on error. + :a regs: return, dirent + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + +OPENDIR +------- + +.. c:function:: int f_opendir (const char* name) + + | + + Create a connection between a directory and a directory descriptor. Up to 8 + directories may be open at once. + + :Op code: RIA_OP_OPENDIR 0x20 + :C proto: rp6502.h + :param name: Pathname to a directory. + :returns: Directory descriptor. -1 on error. + :a regs: return + :errno: EINVAL, EMFILE, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_OBJECT, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES + + +READDIR +------- + +.. c:function:: int f_readdir (f_stat_t* dirent, int dirdes) + + | + + Returns file or directory info for directory descriptor. + + :Op code: RIA_OP_READDIR 0x21 + :C proto: rp6502.h + :param path: Pathname to a directory entry. + :param dirent: Returned f_stat_t data. + :returns: 0 on success. -1 on error. + :a regs: return, dirent + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + +CLOSEDIR +-------- + +.. c:function:: int f_closedir (int dirdes) + + | + + Release the directory descriptor. Directory descriptor + will rejoin the pool available for use by f_opendir(). + + :Op code: RIA_OP_CLOSEDIR 0x22 + :C proto: rp6502.h + :param dirdes: Directory descriptor from f_opendir(). + :returns: 0 on success. -1 on error. + :a regs: return, dirdes + :errno: EINVAL, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT + + +TELLDIR +------- + +.. c:function:: long f_telldir (int dirdes) + + | + + Returns the read position of the directory descriptor. + + :Op code: RIA_OP_TELLDIR 0x23 + :C proto: rp6502.h + :param dirdes: Directory descriptor from f_opendir(). + :returns: Read position. -1 on error. + :a regs: dirdes + :errno: EINVAL, EBADF + + +SEEKDIR +------- + +.. c:function:: int f_seekdir (long offs, int dirdes) + + | + + Set the read position for the directory descriptor. Internally, + the FatFs directory read position can only move forward by one, + so use this for convienence, not performance. + + :Op code: RIA_OP_SEEKDIR 0x24 + :C proto: rp6502.h + :param dirdes: Directory descriptor from f_opendir(). + :returns: Read position. -1 on error. + :a regs: return, dirdes + :errno: EINVAL, EBADF, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + +REWINDDIR +--------- + +.. c:function:: int f_rewinddir (int dirdes) + + | + + Rewind the read position of the directory descriptor. + + :Op code: RIA_OP_REWINDDIR 0x25 + :C proto: rp6502.h + :param dirdes: Directory descriptor from f_opendir(). + :returns: 0 on success. -1 on error. + :a regs: dirdes + :errno: EINVAL, EBADF, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + +CHMOD +----- + +.. c:function:: int f_chmod (const char* path, unsigned char attr, unsigned char mask) + + | + + Change the attributes of a file or directory. + + :Op code: RIA_OP_CHMOD 0x26 + :C proto: rp6502.h + :param path: Pathname to a file or directory. + :param attr: New bitfield of attributes. See table. + :param mask: Only attributes with bits set here will be changed. + :returns: 0 on success. -1 on error. + :a regs: return, mask + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + .. list-table:: + :header-rows: 1 + :widths: 25 25 + + * - Attribute + - Bit + * - Read Only + - 0x01 + * - Hidden + - 0x02 + * - System + - 0x04 + * - Directory + - 0x10 + * - Archive + - 0x20 + + +UTIME +----- + +.. c:function:: int f_utime (const char* path, unsigned fdate, unsigned ftime, unsigned crdate, unsigned crtime) + + | + + Update the date and time stamps of a file or directory. A date of 0 (invalid) leaves the date and time unchanged. + + :Op code: RIA_OP_UTIME 0x27 + :C proto: rp6502.h + :param path: Pathname to a file or directory. + :param fdate: Modification date. + :param ftime: Modification time. + :param crdate: Creation date. + :param crtime: Creation time. + :returns: 0 on success. -1 on error. + :a regs: return, mask + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + .. list-table:: Date + :header-rows: 0 + :widths: 10 25 + + * - bit15:9 + - Years since 1980 (0..127) + * - bit8:5 + - Month (1..12) + * - bit4:0 + - Day (1..31) + + .. list-table:: Time + :header-rows: 0 + :widths: 10 25 + + * - bit15:11 + - Hour (0..23) + * - bit10:5 + - Minute (0..59) + * - bit4:0 + - Second / 2 (0..29) + + +MKDIR +----- + +.. c:function:: int f_mkdir (const char* name) + + | + + Make a new directory entry. + + :Op code: RIA_OP_MKDIR 0x28 + :C proto: rp6502.h + :param name: Pathname of the directory to create. + :returns: 0 on success. -1 on error. + :a regs: return + :errno: FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + +CHDIR +----- + +.. c:function:: int chdir (const char* name) + + | + + Change to a directory entry. + + :Op code: RIA_OP_CHDIR 0x29 + :C proto: unistd.h + :param name: Pathname of the directory to make current. + :returns: 0 on success. -1 on error. + :a regs: return + :errno: FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + +CHDRIVE +------- + +.. c:function:: int f_chdrive (const char* name) + + | + + Change durrent drive. Eight USB MSC drives are formally named "USB0:" to "USB7:" + with shortcuts "0:" to "7:". + + :Op code: RIA_OP_CHDRIVE 0x2A + :C proto: rp6502.h + :param name: Pathname of the directory to make. + :returns: 0 on success. -1 on error. + :a regs: return + :errno: FR_INVALID_DRIVE + + +GETCWD +------- + +.. c:function:: int f_getcwd (char* name, int size) + + | + + Get the current working directory. Size is ignored by the OS + but the C wrapper will use it. + + :Op code: RIA_OP_GETCWD 0x2B + :C proto: rp6502.h + :param name: The returned directory. + :returns: Size of returned name. -1 on error. + :errno: ENOMEM, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE + + +SETLABEL +-------- + +.. c:function:: int f_setlabel (const char* name) + + | + + Change the volume label. Max 11 characters. + + :Op code: RIA_OP_SETLABEL 0x2C + :C proto: rp6502.h + :param name: Label with optional volume name. + :returns: 0 on success. -1 on error. + :a regs: return + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT + + +GETLABEL +-------- + +.. c:function:: int f_getlabel (const char* path, char* label) + + | + + Get the volume label. Label must have room for (11+1) characters. + + :Op code: RIA_OP_GETLABEL 0x2D + :C proto: rp6502.h + :param name: Volume name. + :param label: Storage for returned label. + :returns: Size of returned label. -1 on error. + :a regs: return + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT + + +GETFREE +------- + +.. c:function:: int f_getfree (const char* name, unsigned long* free, unsigned long* total) + + .. code-block:: c + + struct { + unsigned long free; + unsigned long total; + }; + + Get the volume free and total space in number of 512 bytes blocks. + + :Op code: RIA_OP_GETFREE 0x2E + :C proto: rp6502.h + :param name: Volume name. + :param free: Storage for returned value. + :param total: Storage for returned value. + :returns: 0 on success. -1 on error. + :a regs: return + :errno: EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT + + +EXIT +---- + +.. c:function:: void exit (int status) + + | + + Halt the 6502 and return the console to RP6502 monitor control. This + is the only operation that does not return. RESB will be pulled down + before the next instruction can execute. Status is currently ignored + but will be used in the future. + + In general, dropping the user back to the monitor is discouraged. But + calling exit() or falling off main() is preferred to locking up. + + :Op code: RIA_OP_EXIT 0xFF + :C proto: stdlib.h + :a regs: status + :param status: 0 is success, 1-255 for error. diff --git a/docs/source/ria.rst b/docs/source/ria.rst index 3c57ce8..740cd14 100644 --- a/docs/source/ria.rst +++ b/docs/source/ria.rst @@ -1,81 +1,81 @@ +==================== RP6502-RIA -########## +==================== -Rumbledethumps Picocomputer 6502 Interface Adapter. +RP6502 - RP6502 Interface Adapter -.. contents:: Table of Contents - :local: -1. Introduction -=============== +Introduction +============ The RP6502 Interface Adapter (RIA) is a Raspberry Pi Pico 2 with -RP6502-RIA firmware. The RIA provides all essential services to support a -WDC W65C02S microprocessor. - -1.1. Features of the RP6502-RIA -------------------------------- - -* Advanced CMOS process technology for low power consumption -* Real time clock with automatic daylight savings time -* 6502 reset and clock management -* ROM loader instead of ROM chips -* A proper UART -* Stereo audio -* USB keyboards and mice -* USB mass storage aka thumb drives -* USB gamepads for up to four player fun -* PIX bus for GPUs like the RP6502-VGA - -2. Functional Description -========================= - -The RIA must be installed at $FFE0-$FFFF and must be in control of RESB -and PHI2. These are the only requirements. Everything else about your -Picocomputer can be customized. - -A new RIA will boot to the console interface. This console can be accessed -in one of three ways: from a VGA monitor and USB keyboard if you are using -an RP6502-VGA; from the USB CDC device which the RP6502-VGA presents when -plugged into a host PC like a development system; or from UART RX/TX -(115200 8N1) pins on the RIA if you aren't using an RP6502-VGA. The -console interface is not currently documented here. The built-in help is -extensive and always up-to-date. Type ``help`` to get started and don't -forget there is deep help like ``help set phi2``. - -The console interface is not meant to be an operating system CLI. -Everything about its design is meant to achieve two goals. The first is to -enable installing ROM files to the RIA EEPROM which can then boot on power -up—this delivers the instant-on experience of early home computers. The -other goal is to enable easy development and experimentation—you can load -ROMs directly from a USB drive or send them from a development system. - -2.1. Reset ----------- - -When the 6502 is in reset, meaning RESB is low and it is not running, the -RIA console is available for use. If the 6502 has crashed or the current -application has no way to exit, you can put the 6502 back into reset in -two ways. - -Using a USB keyboard, press CTRL-ALT-DEL. The USB stack runs on the Pi -Pico so this will work even if the 6502 has crashed. - -Over the UART, send a break. The tools included with the "Hello, world!" -project templates use this to stop the 6502, upload a new ROM, and execute -the new ROM. All with the push of one button. - -WARNING! Do not hook up a physical button to RESB. The RIA must remain in -control of RESB. What you probably want is the reset that happens from the -RIA RUN pin. We call this a reboot. The reference hardware reboot button -is hooked up to the RIA RUN pin. Rebooting the Pi Pico RIA like this will -cause any configured boot ROM to load, like at power on. Resetting the -6502 from keyboard or UART will only return you to the console interface, -which is great for development and hacking. - - -2.2. Registers --------------- +:doc:`ria` firmware. The :doc:`ria` provides all essential services to +support a WDC W65C02S microprocessor. + +The :doc:`ria` must be installed at $FFE0-$FFFF and must be in control of +RESB and PHI2. These are the only requirements. Everything else about +your Picocomputer can be customized. Even the :doc:`vga` is optional. + +A new :doc:`ria` will boot to the RP6502 monitor which you can access from the +console. The console can be accessed in one of three ways: from a VGA +monitor and USB or Bluetooth keyboard if you are using an :doc:`vga`; +from the USB CDC device which the :doc:`vga` presents when plugged +into a host PC like a development system; or from UART RX/TX +(115200 8N1) pins on the RIA if you aren't using an :doc:`vga`. The +monitor is not documented here beyond highlighting some common +commands. The built-in help is extensive and always up-to-date. Type +``help`` to get started and don't forget there is deep help like +``help set phi2``. + +The RP6502 monitor is not an operating system shell. It is analogous to a +UEFI shell. The RP6502 monitor is primarily designed to load ROMs. +It also has a small amount of hardware and locale +configuration, which is intentionally kept minimal. + +Loading ROMs in .rp6502 format is done with the ``load`` +command. Type ``help load`` to learn about the file format for ROMs. +These aren't ROMs in the traditional (obsolete) sense. A ROM is a file +that contains a memory image to be loaded in RAM before starting the +6502. The :doc:`ria` includes 1MB of EEPROM which you can ``install`` ROMs to. +Once a ROM is installed, you can run it directly or ``set boot`` so it +loads when the :doc:`ria` boots. + +Some of the monitor commands, like ``upload`` and ``binary`` are +designed for use by developer tools. The rp6502.py script, included +with the examples and templates, can be used to automate packaging of a +ROM and executing it. + + +Reset +===== + +It helps to think about reset as two states instead of a pulse on +RESB. When reset is low, the 6502 is stopped and the console is +connected to the RP6502 monitor. When reset is high, the 6502 is running +and the console is connected both stdio in the :doc:`os` and the UART TX/RX +registers described below. + +If you want to move reset from low to high, either ``load`` a ROM with +a reset vector, or use the ``reset`` command if you have prepared RAM +some other way. + +To move reset from high to low and return to the monitor, even with a +crashed or halted 6502, you have two options: + +1. Using a Bluetooth or USB keyboard, press CTRL-ALT-DEL. +2. Send a break to the RIA UART. + +WARNING! Do not hook up a physical button to RESB. The :doc:`ria` must remain +in control of RESB. What you probably want is the reset that happens +from the RIA RUN pin. We call this a ``reboot``. The reference hardware +reboot button is hooked up to the RIA RUN pin. Rebooting the :doc:`ria` +like this will cause any configured boot ROM to load, like at power +on. Resetting the 6502 from keyboard or UART will only return you to +the RP6502 console. + + +Registers +========= .. list-table:: :widths: 5 5 90 @@ -87,8 +87,10 @@ which is great for development and hacking. * - $FFE0 - READY - Flow control for UART FIFO. - * bit 7 - TX FIFO not full. OK to send. - * bit 6 - RX FIFO has data ready. + + * bit 7 - TX FIFO not full. OK to send. + * bit 6 - RX FIFO has data ready. + * - $FFE1 - TX - Write bytes to the UART. @@ -97,7 +99,8 @@ which is great for development and hacking. - Read bytes from the UART. * - $FFE3 - VSYNC - - Increments every 1/60 second when PIX VGA device is connected. + - Increments every 1/60 second when PIX VGA device 1 is + connected. * - $FFE4 - RW0 - Read or write the XRAM referenced by ADDR0. @@ -120,7 +123,7 @@ which is great for development and hacking. - Address of XRAM for RW1. * - $FFEC - XSTACK - - 512 bytes for passing call parameters. + - 512 bytes for OS call stack. * - $FFED - ERRNO_LO - Low byte of errno. All errors fit in this byte. @@ -129,29 +132,30 @@ which is great for development and hacking. - Ensures errno is optionally a 16-bit int. * - $FFEF - OP - - Write the API operation id here to begin a kernel call. + - Write the OS operation id here to begin an OS call. * - $FFF0 - IRQ - - Set bit 0 high to enable VSYNC interrupts. Verify source with - VSYNC then read or write this register to clear interrupt. + - Set bit 0 high to enable VSYNC interrupts. Verify source + with VSYNC increment then read or write this register to clear + interrupt. * - $FFF1 - RETURN - - Always $80, BRA. Entry to blocking API return. + - Always $80, BRA. Entry to blocking OS call. * - $FFF2 - BUSY - - Bit 7 high while operation is running. + - Bit 7 high while OS operation is running. * - $FFF3 - LDA - Always $A9. * - $FFF4 - A - - Kernel register A. + - OS call register A. * - $FFF5 - LDX - Always $A2. * - $FFF6 - X - - Kernel register X. + - OS call register X. * - $FFF7 - RTS - Always $60. @@ -172,57 +176,60 @@ which is great for development and hacking. - BRK/IRQB - 6502 vector. - -2.3. UART ---------- +UART +---- Easy and direct access to the UART RX/TX pins of the :doc:`ria` is available from $FFE0-$FFE2. The ready flags on bits 6-7 enable testing -with the BIT operator. You may choose to use these or STDIN and STDOUT -from the :doc:`api`. Using the UART directly while a STDIN or STDOUT -kernel function is in progress will result in undefined behavior. +with the BIT operator. You may choose to use these or stdio +from the :doc:`os`. Using the UART directly while a stdio +OS function is in progress will result in undefined behavior. +The UART hardware runs at 115200 bps, 8 bit words, no parity, 1 stop bit. -2.4. Extended RAM (XRAM) ------------------------- +Extended RAM (XRAM) +------------------- -RW0 and RW1 are two portals to the same 64K XRAM. Having only one portal -would make moving XRAM very slow since data would have to buffer in 6502 -RAM. Ideally, you won't move XRAM and can use the pair for better -optimizations. +RW0 and RW1 are two portals to the same 64K XRAM. Having only one +portal would make moving XRAM very slow since data would have to +buffer in 6502 RAM. Ideally, you won't move XRAM and can use the pair +for better optimizations. -STEP0 and STEP1 are reset to 1. These are signed so you can go backwards -and reverse data. These adders allow for very fast sequential access, -which typically makes up for the slightly slower random access compared -to 6502 RAM. +STEP0 and STEP1 are reset to 1. These are signed so you can go +backwards and reverse data. These adders allow for very fast sequential +access, which typically makes up for the slightly slower random access +compared to 6502 system RAM. -RW0 and RW1 are latching. This is important to remember when other systems -change XRAM. For example, when using read_xram() to load XRAM from a mass -storage device, this will not work as expected: +RW0 and RW1 are latching. This is important to remember when other +systems change XRAM. For example, when using read_xram() to load XRAM +from a mass storage device, this will not work as expected: .. code-block:: C - RIA_ADDR0 = 0x1000; + RIA.addr0 = 0x1000; read_xram(0x1000, 1, fd); - uint8_t result = RIA_RW0; // wrong + uint8_t result = RIA.rw0; // wrong -Setting ADDR after the expected XRAM change will latch RW to the latest -value. +Setting ADDR after the expected XRAM change will latch RW to the +latest value. .. code-block:: C read_xram(0x1000, 1, fd); - RIA_ADDR0 = 0x1000; - uint8_t result = RIA_RW0; // correct + RIA.addr0 = 0x1000; + uint8_t result = RIA.rw0; // correct -2.5. Extended Stack (XSTACK) ----------------------------- +Extended Stack (XSTACK) +----------------------- This is 512 bytes of last-in, first-out, top-down stack used for the -fastcall mechanism described in the :doc:`api`. Reading past the end is -guaranteed to return zeros. Simply write to push and read to pull. +fastcall mechanism described in the :doc:`os`. Reading past the end +is guaranteed to return zeros. Simply write to push and read to pull. -2.6. Extended Registers (XREG) ------------------------------- +Extended Registers (XREG) +------------------------- + +The :doc:`RIA` is both the host of the PIX bus (documented below) +and device 0 on the PIX bus. .. list-table:: :widths: 5 5 90 @@ -245,25 +252,26 @@ guaranteed to return zeros. Simply write to push and read to pull. - See Programmable Sound Generator section -3. Pico Information Exchange (PIX) -================================== +Pico Information Exchange (PIX) +=============================== -The limited number of GPIO pins on the Raspberry Pi Pico required creating -a new bus for high bandwidth devices like video systems. This is an -addressable broadcast system which any number of devices can listen to. +The limited number of GPIO pins on the Raspberry Pi Pico required +creating a new bus for high bandwidth devices like video systems. This +is an addressable broadcast system which any number of devices can +listen to. -3.1. Physical layer -------------------- +Physical layer +-------------- -The physical layer is designed to be easily decoded by Pi Pico PIO, which -is just a fancy shift register. The signals used are PHI2 and PIX0-3. -This is a double data rate bus with PIX0-3 shifted left on both -transitions of PHI2. A frame consists of 32 bits transmitted over 4 cycles -of PHI2. +The physical layer is designed to be easily decoded by Pi Pico PIO, +which is just a fancy shift register. The signals used are PHI2 and +PIX0-3. This is a double data rate bus with PIX0-3 shifted left on +both transitions of PHI2. A frame consists of 32 bits transmitted over +4 cycles of PHI2. Bit 28 (0x10000000) is the framing bit. This bit will be set in all -messages. An all-zero payload is repeated on device ID 7 when the bus is -idle. A receiver will synchronize by ensuring PIX0 is high on a low +messages. An all-zero payload is repeated on device ID 7 when the bus +is idle. A receiver will synchronize by ensuring PIX0 is high on a low transition of PHI2. If it is not, stall until the next clock cycle. Bits 31-29 (0xE0000000) indicate the device ID number for a message. @@ -275,71 +283,70 @@ Device 1 is allocated to :doc:`vga`. Devices 2-6 are available for user expansion. -Device 7 is used for synchronization. Because 0xF0000000 is hard to miss -on test equipment. +Device 7 is used for synchronization. Because 0xF0000000 is hard to +miss on test equipment. Bits 27-24 (0x0F000000) indicate the channel ID number for a message. Each device can have 16 channels. -Bits 23-16 (0x00FF0000) indicate the register address in the channel on -the device. +Bits 23-16 (0x00FF0000) indicate the register address in the channel +on the device. Bits 15-0 (0x0000FFFF) is a value to store in the register. -3.2. PIX Extended RAM (XRAM) ----------------------------- +PIX Extended RAM (XRAM) +----------------------- -All changes to the 64KB of XRAM on the RIA will be broadcast on PIX -device 0. Bits 15-0 contain the XRAM address. Bits 23-16 contain the XRAM -data. This goes out on the wire, but is never seen by the SDK. Device 0, -as seen by the SDK, is the RIA itself and has no need to go out on the -wire. +All changes to the 64KB of XRAM on the RIA will be broadcast to PIX +device 0. Bits 15-0 contain the XRAM address. Bits 23-16 contain the +XRAM data. -PIX devices will maintain a replica of the XRAM they use. Typically, all -64K is replicated and an XREG set by the application will point to a -configuration structure in XRAM. +PIX devices will maintain a replica of the XRAM they use. Typically, +all 64K is replicated and an XREG set by a 6502 application will +install virtual hardware at a location in XRAM. -3.3. PIX Extended Registers (XREG) ----------------------------------- +PIX Extended Registers (XREG) +----------------------------- -PIX devices may use bits 27-0 however they choose. The suggested division -of these bits is: +PIX devices may use bits 27-0 however they choose. The suggested +division of these bits is: -Bits 27-24 indicate a channel. For example, the RIA device has a channel -for audio, a channel for keyboard and mouse, a channel for Wifi, and so -on. Bits 23-16 contain an extended register address. Bits 15-0 contain the -payload. +Bits 27-24 indicate a channel. For example, the RIA device has a +channel for audio, a channel for keyboard, a channel for mice, and so +on. Bits 23-16 contain an extended register address. Bits 15-0 contain +the value to be stored. So we have seven PIX devices, each with 16 internal channels having 256 -16-bit registers. The idea is to use extended registers to point to -structures in XRAM. Changing XREG is setup; changing XRAM causes the -device to respond. +16-bit registers. The idea is to use these extended registers to +configure virtual hardware and map it into extended memory. -4. Keyboard -=========== +Keyboard +======== -The RIA can provide direct access to keyboard data. This is intended for -applications that need to detect both key up and down events or the +The RIA can provide direct access to keyboard data. This is intended +for applications that need to detect both key up and down events or the modifier keys. You may instead use the UART or stdin if you don't need this kind of direct access. -Enable and disable direct keyboard access by mapping it to an address in -extended RAM. +Enable and disable direct keyboard access by mapping it to an address +in XRAM. .. code-block:: C xreg(0, 0, 0x00, xaddr); // enable xreg(0, 0, 0x00, 0xFFFF); // disable + xreg_ria_keyboard(xaddr); // macro shortcut -Extended RAM will be continuously updated with a bit array of USB HID -keyboard codes. Note that these are not the same as PS/2 scancodes. Each -bit represents one key with the first four bits having special meaning: +XRAM will be continuously updated with a bit array of USB HID +keyboard codes. Note that these are not the same as PS/2 scancodes. +Each bit represents one key with the first four bits/codes having special +meaning: -| * 0 - No key pressed -| * 1 - Overflow - too many keys pressed -| * 2 - Num Lock on -| * 3 - Caps Lock on +- 0 - No key pressed +- 1 - Num Lock on +- 2 - Caps Lock on +- 3 - Scroll Lock on .. code-block:: C @@ -348,18 +355,19 @@ bit represents one key with the first four bits having special meaning: (1 << (code & 7))) -5. Mouse -======== +Mouse +===== -The RIA can provide direct access to mouse information. Enable and disable -by mapping it to an address in extended RAM. +The RIA can provide direct access to mouse information. Enable and +disable by mapping it to an address in XRAM. .. code-block:: C xreg(0, 0, 0x01, xaddr); // enable xreg(0, 0, 0x01, 0xFFFF); // disable + xreg_ria_mouse(xaddr); // macro shortcut -This sets the address in extended RAM for a structure containing direct +This sets the address in XRAM for a structure containing direct mouse input. .. code-block:: C @@ -372,61 +380,63 @@ mouse input. uint8_t pan; } mouse; -The amount of movement is computed by keeping track of the previous values -and subtracting from the current value. Vsync timing (60Hz) isn't always -fast enough. For perfect mouse input, use an ISR at 8ms or faster (125Hz). +The amount of movement is computed by way of the application subtracting +the previous value from the current value. Vsync timing (60Hz) is period correct +but isn't fast enough by modern standards. For perfect mouse input, use an ISR +at 8ms or faster (125Hz). It is recommended that applications consider the canvas resolution when -interpreting the movement. For 640x480 and 640x360 resolutions, each unit -of movement equates to one pixel. For 320x240 and 320x180 resolutions, two -units of movement for each pixel. +interpreting the movement. For 640x480 and 640x360 resolutions, each +unit of movement equates to one pixel. For 320x240 and 320x180 +resolutions, use two units of movement for each pixel. .. code-block:: C int8_t delta_x = current_x - prev_x; + int8_t delta_y = current_y - prev_y; -| Mouse buttons are a bitfield: -| * 0 - LEFT -| * 1 - RIGHT -| * 2 - MIDDLE -| * 3 - BACKWARD -| * 4 - FORWARD +Mouse buttons are a bitfield: +- 0 - LEFT +- 1 - RIGHT +- 2 - MIDDLE +- 3 - BACKWARD +- 4 - FORWARD -6. Gamepads -=========== -The RIA supports up to four gamepads. There are drivers for Generic HID, -XInput, and Playstation controllers. Unfortunately, the TinyUSB stack that -the RIA uses is unstable on the Pi Pico and the information needed to fix -is not part of the Pi Pico documentation. XInput is currently disabled and -you may find USB instability on other devices. +Gamepads +======== -Some gamepads let you select between HID/DInput/Android, XInput, and other -system. Choose HID/DInput/Android for the best chance of working. +The :doc:`ria` supports up to four gamepads. There are drivers for Generic HID, +XInput, and Playstation controllers. Unfortunately, the TinyUSB stack +that the RIA uses is unstable on the Pi Pico and the information needed +to fix it is not part of the Pi Pico documentation. XInput is currently +disabled and you may find USB instability on other devices. -Modern gamepads all have evolved to the same four buttons and two sticks -design with some minor variations in the face buttons which are either -XY/AB, YX/BA, or Square/Triangle/Cross/Circle. This is generally of no -consequence to the application unless those buttons are intended to -represent a direction. In that case, the Square/Triangle/Cross/Circle and -XY/AB layouts are "the official" layout of the RP6502. You can, of course, -do your own thing and request players use a specific gamepad. +Some gamepads let you select between HID/DInput/Android, XInput, and +other systems. Choose HID/DInput/Android for the best chance of working. -Be aware that some gamepads will attempt to charge over USB. You can use -a powered USB hub if needed. +Modern gamepads have all evolved to the same four face buttons, d-pad, +dual analog sticks, and quad shoulders. The minor variations of the four +face buttons are XY/AB, YX/BA, or Square/Triangle/Cross/Circle. This is +generally of no consequence to the application unless those buttons are +intended to represent a direction. In that case, the +Square/Triangle/Cross/Circle and XY/AB layouts are "the official" layout +of the RP6502. You can, of course, do your own thing and request players +use a specific gamepad or include a "AB or BA" option. -Enable and disable access to the RIA gamepad XRAM registers by setting the -extended register. The register value is the XRAM start address of the -gamepad registers. Any invalid address disables the gamepads. +Enable and disable access to the RIA gamepad XRAM registers by setting +the extended register. The register value is the XRAM start address of +the gamepad data. Any invalid address disables the gamepads. .. code-block:: C - xreg(0, 0, 2, xaddr); // enable - xreg(0, 0, 2, 0xFFFF); // disable + xreg(0, 0, 2, xaddr); // enable + xreg(0, 0, 2, 0xFFFF); // disable + xreg_ria_gamepad(xaddr); // macro shortcut -Extended memory will be continuously updated with gamepad information. The -10-byte structure described here repeats for a total of 40 bytes +Extended memory will be continuously updated with gamepad information. +The 10-byte structure described here repeats for a total of 40 bytes representing four gamepads. The upper bits of the DPAD register are used to indicate if a gamepad is @@ -435,8 +445,8 @@ when a gamepad for that player slot is connected. The Sony bit indicates that the player is using a PlayStation-style gamepad with Circle/Cross/Square/Triangle button faces. -Note that there are both digital and analog values for the left and right -analog sticks and analog triggers L2/R2. This lets an application +Note that there are both digital and analog values for the left and +right analog sticks and analog triggers L2/R2. This lets an application completely ignore the analog values if it desires. Applications supporting L2 and R2 should be aware that some gamepads @@ -455,48 +465,44 @@ are encouraged to support both the dpad and left stick (merged). - Description * - 0 - DPAD - - - * bit 0: Direction pad up - * bit 1: Direction pad down - * bit 2: Direction pad left - * bit 3: Direction pad right - * bit 4: Reserved - * bit 5: Reserved - * bit 6: Sony button faces - * bit 7: Connected + - * bit 0: Direction pad up + * bit 1: Direction pad down + * bit 2: Direction pad left + * bit 3: Direction pad right + * bit 4: Reserved + * bit 5: Reserved + * bit 6: Sony button faces + * bit 7: Connected * - 1 - STICKS - - - * bit 0: Left stick up - * bit 1: Left stick down - * bit 2: Left stick left - * bit 3: Left stick right - * bit 4: Right stick up - * bit 5: Right stick down - * bit 6: Right stick left - * bit 7: Right stick right + - * bit 0: Left stick up + * bit 1: Left stick down + * bit 2: Left stick left + * bit 3: Left stick right + * bit 4: Right stick up + * bit 5: Right stick down + * bit 6: Right stick left + * bit 7: Right stick right * - 2 - BTN0 - - - * bit 0: A or Cross - * bit 1: B or Circle - * bit 2: C or Right Paddle - * bit 3: X or Square - * bit 4: Y or Triangle - * bit 5: Z or Left Paddle - * bit 6: L1 - * bit 7: R1 + - * bit 0: A or Cross + * bit 1: B or Circle + * bit 2: C or Right Paddle + * bit 3: X or Square + * bit 4: Y or Triangle + * bit 5: Z or Left Paddle + * bit 6: L1 + * bit 7: R1 * - 3 - BTN1 - - - * bit 0: L2 - * bit 1: R2 - * bit 2: Select/Back - * bit 3: Start/Menu - * bit 4: Home button - * bit 5: L3 - * bit 6: R3 - * bit 7: Undefined + - * bit 0: L2 + * bit 1: R2 + * bit 2: Select/Back + * bit 3: Start/Menu + * bit 4: Home button + * bit 5: L3 + * bit 6: R3 + * bit 7: Undefined * - 4 - LX - Left analog stick X position. -128=left, 0=center, 127=right @@ -517,8 +523,8 @@ are encouraged to support both the dpad and left stick (merged). - Right analog trigger position. 0-255 -1. Programmable Sound Generator -=============================== +Programmable Sound Generator +============================= The RIA includes a Programmable Sound Generator (PSG). It is configured with extended register device 0 channel 1 address 0x00. @@ -530,8 +536,8 @@ with extended register device 0 channel 1 address 0x00. * PWM for all waveforms. Each of the eight oscillators requires eight bytes of XRAM for -configuration. The unused byte is padding so multiplication is a fast bit -shift. +configuration. The unused byte is padding so multiplication is a fast +bit shift. .. code-block:: C @@ -546,21 +552,23 @@ shift. unsigned char unused; } ria_psg_t; -Internally, the audio is generated by Pulse Width Modulation. A decoupling -and low-pass filter circuit converts the digital signal into line-level -analog. +Internally, the audio is generated by Pulse Width Modulation. A +decoupling and low-pass filter circuit converts the digital signal +into line-level analog. Enable and disable the RIA PSG by setting the extended register. The -register value is the XRAM start address for the 64 bytes of config. This -start address must be int-aligned. Any invalid address disables the PSG. +register value is the XRAM start address for the 64 bytes of config. +This start address must be int-aligned. Any invalid address disables +the PSG. .. code-block:: C xreg(0, 1, 0x00, xaddr); // enable xreg(0, 1, 0x00, 0xFFFF); // disable -All configuration changes take effect immediately. This allows for effects -like panning, slide instruments, and other CPU-driven shenanigans. +All configuration changes take effect immediately. This allows for +effects like panning, slide instruments, and other CPU-driven +shenanigans. The gate is checked at the sample rate of 24kHz. If, for example, you unset and set it between one pair of audio output samples, then it will @@ -580,20 +588,28 @@ not begin a new ADSR cycle. waveforms. * - vol_attack - Attack volume and rate. - * bits 7-4 - 0-15 volume attenuation. - * bits 3-0 - 0-15 attack rate. + + * bits 7-4 - 0-15 volume attenuation. + * bits 3-0 - 0-15 attack rate. + * - vol_decay - Decay volume and rate. - * bits 7-4 - 0-15 volume attenuation. - * bits 3-0 - 0-15 decay rate. + + * bits 7-4 - 0-15 volume attenuation. + * bits 3-0 - 0-15 decay rate. + * - wave_release - Waveform and release rate. - * bits 7-4 - 0=sine, 1=square, 2=sawtooth, 3=triangle, 4=noise. - * bits 3-0 - 0-15 release rate. + + * bits 7-4 - 0=sine, 1=square, 2=sawtooth, 3=triangle, + 4=noise. + * bits 3-0 - 0-15 release rate. + * - pan_gate - Stereo pan and gate. - * bits 7-1 - Pan -63(left) to 63(right). - * bit 0 - 1=attack/decay/sustain, 0=release. + + * bits 7-1 - Pan -63(left) to 63(right). + * bit 0 - 1=attack/decay/sustain, 0=release. Value table. ADR rates are the time it takes for a full volume change. Volume attenuation is logarithmic. diff --git a/docs/source/ria_w.rst b/docs/source/ria_w.rst index a4f2ff4..0dec970 100644 --- a/docs/source/ria_w.rst +++ b/docs/source/ria_w.rst @@ -1,54 +1,68 @@ +================================= RP6502-RIA-W -############ +================================= -Rumbledethumps Picocomputer 6502 Interface Adapter W +RP6502 - RP6502 Interface Adapter W -.. contents:: Table of Contents - :local: -1. Introduction -=============== +Introduction +============ -The **RP6502 Interface Adapter W (RIA W)** is a Raspberry Pi Pico 2 W running the RP6502-RIA-W firmware. The RIA W provides all the features of the :doc:`ria` plus integrated wireless services, as described below. +The **RP6502 Interface Adapter W** is a Raspberry Pi Pico 2 W running +the RP6502-RIA-W firmware. The :doc:`ria_w` provides all the features +of the :doc:`ria` plus wireless services, as described below. -2. WiFi Setup -============= -The RIA W uses an Infineon CYW43439 chip supporting Wi-Fi 4 (802.11n). Configuration is performed via the console interface. +WiFi Setup +========== + +The RP6502-RIA-W supports Wi-Fi 4 (802.11n). Configuration is performed +via the console interface. - **Enable/Disable Radio:** - Use ``SET RF (0|1)`` to enable (1, default) or disable (0) all radios without affecting other settings. + Use ``SET RF (0|1)`` to enable (1, default) or disable (0) all radios + without affecting other settings. - **Set Country Code:** - ``SET RFCC (cc|-)`` sets the WiFi country code for optimal performance (e.g., ``US``, ``GB``). Use ``help set rfcc`` to list supported codes. Use ``-`` to reset to the worldwide default. + ``SET RFCC (cc|-)`` sets the WiFi country code for optimal performance + (e.g., ``US``, ``GB``). Use ``help set rfcc`` to list supported codes. + Use ``-`` to reset to the worldwide default. - **Set Network Name (SSID):** - ``SET SSID (ssid|-)`` sets your WiFi network name (Service Set Identifier). Use ``-`` to clear. + ``SET SSID (ssid|-)`` sets your WiFi network name (Service Set + Identifier). Use ``-`` to clear. - **Set Network Password:** ``SET PASS (pass|-)`` sets your WiFi password. Use ``-`` to clear. - **Check WiFi Status:** - Use the ``status`` command to view current WiFi connection and settings. + Use the ``status`` command to view current WiFi connection and + settings. + -3. Network Time Protocol (NTP) -============================== +Network Time Protocol (NTP) +=========================== -The real-time clock (RTC) automatically synchronizes with internet time servers when connected. -Check NTP status with the `status` command. +The real-time clock (RTC) automatically synchronizes with internet time +servers when connected. Check NTP status with the ``status`` command. - **Set Time Zone:** - To use local time instead of UTC, set your time zone with ``SET TZ``. Use ``help set tz`` for guidance. Daylight saving adjustments are automatic if your locale observes them. + To use local time instead of UTC, set your time zone with ``SET TZ``. + Use ``HELP SET TZ`` for guidance. Daylight saving adjustments are + automatic if your locale observes them. -Once WiFi and time zone are configured, timekeeping is automatic—no battery required and no drift to worry about. +Once WiFi and time zone are configured, timekeeping is automatic. -4. Modem Emulation -================== -The RIA W can emulate a Hayes modem for BBS access. Beware that raw TCP and telnet protocols are plain text in transit. +Modem Emulation +=============== + +The :doc:`ria_w` can emulate a Hayes modem for BBS access. Beware that +raw TCP and telnet protocols are plain text in transit. - **AT Commands:** - The modem interface supports standard AT commands for dialing, answering, and configuration. + The modem interface supports standard AT commands for dialing, + answering, and configuration. Example AT commands: @@ -72,26 +86,26 @@ Example AT commands: - ``AT+SSID=your_ssid`` and ``AT+SSID?`` — Access RIA setting SSID - ``AT+PASSS=your_ssid`` and ``AT+PASS?`` — Access RIA setting PASS -A full telnet stack has yet to be written so all connections are raw TCP. +A full telnet stack has yet to be written so all connections are raw +TCP. -"Telephone Numbers" are saved immediately and are not linked to profiles. +"Telephone Numbers" are saved immediately and are not linked to +profiles. -`Please contribute to this documentation. `_ -5. Bluetooth -============ +Bluetooth +========= -The RIA W supports Bluetooth LE (BLE) keyboards, mice, and gamepads. -It does not support the older Bluetooth Classic aka BR/EDR. -The RIA W uses BTStack which can only support one Bluetooth Classic device -at a time so it's not worth the memory. -BLE was introduced in June 2010 with Bluetooth 4.0 so it's not difficult -to find devices but you will find an occassional oddball. Of particular -note are Sony DualShock and DualSense controllers - which you can use on -USB instead. +The :doc:`ria_w` supports Bluetooth LE (BLE) keyboards, mice, and +gamepads. It does not support the older Bluetooth Classic aka BR/EDR. +The RP6502-RIA-W uses BTStack which can only support one Bluetooth +Classic device at a time so it's not worth the memory. BLE was introduced +in June 2010 with Bluetooth 4.0 so it's not difficult to find devices but +you will find an occasional oddball. Of particular note are Sony DualShock +and DualSense controllers - which you can use on USB instead. To add a new device, use monitor command ``set ble 2`` to enable pairing -mode. The LED on the RIA W will blink when in pairing mode. See your device's -manual to enable its pairing mode - probably a button and more blinking. -When the blinking stops, the device is connected and will be remembered -(bonded) so it reconnects automatically in the future. +mode. The LED on the RP6502-RIA-W will blink when in pairing mode. See +your device's manual to enable its pairing mode - probably a button and +more blinking. When the blinking stops, the device is connected and will +be remembered (bonded) so it reconnects automatically in the future. diff --git a/docs/source/vga.rst b/docs/source/vga.rst index eb1b2be..70f2326 100644 --- a/docs/source/vga.rst +++ b/docs/source/vga.rst @@ -1,30 +1,54 @@ +================================== RP6502-VGA -########## - -Rumbledethumps Picocomputer 6502 Video Graphics Array. - -.. contents:: Table of Contents - :local: - -1. Introduction -=============== - -The RP6502 Video Graphics Array is a Raspberry Pi Pico 2 with RP6502-VGA firmware. Its primary data connection is to a :doc:`ria` over a 5-wire PIX bus. More than one VGA module can be put on a PIX bus. Note that all VGA modules share the same 64K of XRAM and only one module can generate frame numbers and vsync interrupts. - -2. Video Programming -==================== - -The design philosophy for the VGA system is to enable the full power of the Pi Pico while maintaining some 8-bit purity. To that end, two paths must be created. The VGA system must help you get the most value from 64K of extended memory (XRAM) and the VGA modes must inflict nostaligia. You may follow either or both paths. - -The VGA system is built around the scanvideo library from Pi Pico Extras. All three planes are enabled with RGB555 color plus transparency. The mode 4 sprite system is from Pi Pico Playground. The programming system and all other modes are original work for the RP6502. - -The RP6502 VGA system exposes per-scanline configuration of the video system to your 6502 application. At the broadest scope we have three planes. Each plane has two layers, a fill layer and a sprite layer. Your application can assign different fill and sprite modes to specific planes and scanlines. There's plenty of fill rate to exceed the capabilities of any classic 8-bit system, but if you like to push the limits then you may see a half-blue screen indicating you went too far. - -The built-in 8x8 and 8x16 fonts are available by using the special XRAM pointer $FFFF. Glyphs 0-127 are ASCII, glyphs 128-255 vary depending on the code page selected. - -The built-in color palettes are accessed by using the special XRAM pointer $FFFF. 1-bit is black and white. 4 and 8-bits point to an ANSI color palette of 16 colors, followed by 216 colors (6x6x6), followed by 24 greys. - -16-bit colors are built with the following bit logic. Setting the alpha bit will make the color opaque. The built-in ANSI color palette has the alpha bit set on all colors except color 0 black. +================================== + +RP6502 - Video Graphics Array + +Introduction +============= + +The RP6502 Video Graphics Array is a Raspberry Pi Pico 2 with +:doc:`vga` firmware. Its primary data connection is to a :doc:`ria` +over a 5-wire PIX bus. More than one VGA module can be put on a PIX +bus. Note that all VGA modules share the same 64K of XRAM and only +the first one will generate frame numbers and vsync interrupts. + +Video Programming +================== + +The VGA system provides virtual video hardware that is similar +to home computer and arcade hardware from the 8-bit and early +16-bit era. It is very easy to add new video modes and sprite +systems. The 6502 application programmer can mix and match these +modes. + +The VGA system is built around the scanvideo library from Pi +Pico Extras. All three planes are enabled with RGB555 color plus +transparency. The mode 4 sprite system is from Pi Pico Playground. +The programming system and all other modes are original work for +the RP6502. + +The RP6502 VGA system exposes per-scanline configuration of the +video system to your 6502 application. At the broadest scope we +have three planes. Each plane has two layers, a fill layer and a +sprite layer. Your application can assign different fill and +sprite modes to specific planes and scanlines. There's plenty of +fill rate to exceed the capabilities of any classic 8-bit system, +but if you like to push the limits then you may see a half-blue +screen indicating you went too far. + +The built-in 8x8 and 8x16 fonts are available by using the special +XRAM pointer $FFFF. Glyphs 0-127 are ASCII, glyphs 128-255 vary +depending on the code page selected. + +The built-in color palettes are accessed by using the special XRAM +pointer $FFFF. 1-bit is black and white. 4 and 8-bits point to an +ANSI color palette of 16 colors, followed by 216 colors (6x6x6), +followed by 24 greys. + +16-bit colors are built with the following bit logic. Setting the +alpha bit will make the color opaque. The built-in ANSI color +palette has the alpha bit set on all colors except color 0 black. .. code-block:: C @@ -32,7 +56,9 @@ The built-in color palettes are accessed by using the special XRAM pointer $FFFF #define COLOR_FROM_RGB5(r,g,b) ((b<<11)|(g<<6)|(r)) #define COLOR_ALPHA_MASK (1u<<5) -Palette information is an array. 8bpp, 4bpp, and 1bpp modes use a palette. 16 bit per pixel modes don't use indexed color and will ignore the palette. Palettes must be 16-bit aligned. +Palette information is an array. 8bpp, 4bpp, and 1bpp modes use a +palette. 16 bit per pixel modes don't use indexed color and will +ignore the palette. Palettes must be 16-bit aligned. .. code-block:: C @@ -41,7 +67,9 @@ Palette information is an array. 8bpp, 4bpp, and 1bpp modes use a palette. 16 bi } palette[2^bits_per_pixel]; -Programming the VGA device is done with PIX extended registers - XREGS. VGA is PIX device ID 1. Registers are 16 bit values addressed by $device:$channel:register. e.g. $1:0:0F +Programming the VGA device is done with PIX extended registers - +XREGS. VGA is PIX device ID 1. Registers are 16 bit values addressed +by $device:$channel:register. e.g. $1:0:0F .. code-block:: C @@ -67,26 +95,39 @@ Setting key registers may return a failure (-1) with errno EINVAL. - Description * - $1:0:00 - CANVAS - - Select a graphics canvas. This clears $1:0:02-$1:0:FF and all scanline programming. The 80 column console canvas is used as a failsafe and therefore not scanline programmable. - * 0 - 80 column console. (4:3 or 5:4) - * 1 - 320x240 (4:3) - * 2 - 320x180 (16:9) - * 3 - 640x480 (4:3) - * 4 - 640x360 (16:9) + - Select a graphics canvas. This clears $1:0:02-$1:0:FF and all + scanline programming. The 80 column console canvas is used as + a failsafe and therefore not scanline programmable. + + * 0 - 80 column console. (4:3 or 5:4) + * 1 - 320x240 (4:3) + * 2 - 320x180 (16:9) + * 3 - 640x480 (4:3) + * 4 - 640x360 (16:9) + * - $1:0:01 - MODE - - Program a mode into a plane of scanlines. $1:0:02-$1:0:FF cleared after programming. Each mode has a section of this document for its own registers. - * 0 - Console - * 1 - Character - * 2 - Tile - * 3 - Bitmap - * 4 - Sprite + - Program a mode into a plane of scanlines. + $1:0:02-$1:0:FF cleared after programming. Each mode has a + section of this document for its own registers. + + * 0 - Console + * 1 - Character + * 2 - Tile + * 3 - Bitmap + * 4 - Sprite Mode 0: Console --------------- -The console may be rendered on any canvas plane. ANSI color 0-black is transparent, which makes it easy to show text over a background image using planes. The console may be a partial screen, but the scanlines must be a multiple of the font height. 640 pixel wide canvases use an 8x16 font for 80 columns. 320 pixel wide canvases use an 8x8 font for 40 columns. Only one console may be visible, programming again will remove the previous console. +The console may be rendered on any canvas plane. ANSI color 0-black +is transparent, which makes it easy to show text over a background +image using planes. The console may be a partial screen, but the +scanlines must be a multiple of the font height. 640 pixel wide +canvases use an 8x16 font for 80 columns. 320 pixel wide canvases +use an 8x8 font for 40 columns. Only one console may be visible, +programming again will remove the previous console. .. list-table:: :widths: 5 5 90 @@ -112,7 +153,9 @@ The console may be rendered on any canvas plane. ANSI color 0-black is transpare Mode 1: Character ----------------- -Character modes have color information for each position on the screen. This is the mode you want for showing text in different colors. +Character modes have color information for each position on the +screen. This is the mode you want for showing text in different +colors. .. list-table:: :widths: 5 5 90 @@ -139,7 +182,8 @@ Character modes have color information for each position on the screen. This is - First scanline to program. BEGIN \<= n \< END * - $1:0:06 - END - - End of scanlines to program. 0 means use canvas height (180-480). + - End of scanlines to program. 0 means use canvas height + (180-480). Config structure may be updated without reprogramming scanlines. @@ -201,7 +245,8 @@ Data is encoded based on the color bit depth selected. uint16_t bg_color; } data[width_chars * height_chars]; -Fonts are encoded in wide format. The first 256 bytes are the first row of each of the 256 glyphs. +Fonts are encoded in wide format. The first 256 bytes are the first +row of each of the 256 glyphs. .. code-block:: C @@ -215,7 +260,10 @@ Fonts are encoded in wide format. The first 256 bytes are the first row of each Mode 2: Tile ------------ -Tile modes have color information encoded in the tile bitmap. This is the mode you want for showing a video game playfield. Hi-res canvases (640x480 and 640x360) support one plane of 1-bit color. Standard canvases (320x240 and 328x180) support two planes of any option. +Tile modes have color information encoded in the tile bitmap. This is +the mode you want for showing a video game playfield. Hi-res canvases +(640x480 and 640x360) support one plane of 1-bit color. Standard +canvases (320x240 and 328x180) support two planes of any option. .. list-table:: :widths: 5 5 90 @@ -242,7 +290,8 @@ Tile modes have color information encoded in the tile bitmap. This is the mode y - First scanline to program. BEGIN \<= n \< END * - $1:0:06 - END - - End of scanlines to program. 0 means use canvas height (180-480). + - End of scanlines to program. 0 means use canvas height + (180-480). Config structure may be updated without reprogramming scanlines. @@ -290,7 +339,9 @@ Tiles are encoded in "tall" bitmap format. Mode 3: Bitmap -------------- -Every pixel can be its own color. 64K XRAM limits the full screen color depth. Monochrome at 640x480, 16 colors at 320x240, 256 colors for 320x180 (16:9). +Every pixel can be its own color. 64K XRAM limits the full screen +color depth. Monochrome at 640x480, 16 colors at 320x240, 256 colors +for 320x180 (16:9). .. list-table:: :widths: 5 5 90 @@ -317,7 +368,8 @@ Every pixel can be its own color. 64K XRAM limits the full screen color depth. M - First scanline to program. BEGIN \<= n \< END * - $1:0:06 - END - - End of scanlines to program. 0 means use canvas height (180-480). + - End of scanlines to program. 0 means use canvas height + (180-480). Config structure may be updated without reprogramming scanlines. @@ -334,9 +386,14 @@ Config structure may be updated without reprogramming scanlines. uint16_t palette_ptr; } config; -Data is the color information packed down to the bit level. 16-bit color encodes the color directly as data. 1, 4, and 8 bit color encodes a palette index as data. +Data is the color information packed down to the bit level. 16-bit +color encodes the color directly as data. 1, 4, and 8 bit color +encodes a palette index as data. -Bit order is traditionally done so that left and right bit shift operations match pixel movement on screen. The reverse bits option change the bit order of 1 and 4 bit modes so bit-level manipulation code is slightly faster and smaller. +Bit order is traditionally done so that left and right bit shift +operations match pixel movement on screen. The reverse bits option +change the bit order of 1 and 4 bit modes so bit-level manipulation +code is slightly faster and smaller. Data for 16 bit color must be 16 bit aligned. @@ -352,9 +409,9 @@ Data for 16 bit color must be 16 bit aligned. Mode 4: Sprite -------------- -Sprites may be drawn over each fill plane. This is the 16-bit sprite system from the Pi Pico Playground. Lower bit depths are planned for a different mode. - -WARNING! Slightly experimental! It is unknown how well the structure data is validated. Please submit a reproducable test program if you encounter a VGA system lockup. +Sprites may be drawn over each fill plane. This is the 16-bit sprite +system from the Pi Pico Playground. Lower bit depths are planned for +a different mode. .. list-table:: :widths: 5 5 90 @@ -383,9 +440,11 @@ WARNING! Slightly experimental! It is unknown how well the structure data is val - First scanline to program. BEGIN \<= n \< END * - $1:0:07 - END - - End of scanlines to program. 0 means use canvas height (180-480). + - End of scanlines to program. 0 means use canvas height + (180-480). -Unused sprites should be moved off screen. Non-affine sprites use this config structure. +Unused sprites should be moved off screen. Non-affine sprites use this +config structure. .. code-block:: C @@ -397,7 +456,10 @@ Unused sprites should be moved off screen. Non-affine sprites use this config st bool has_opacity_metadata; } config[LENGTH]; -Affine sprites apply a 3x3 matrix transform. These are slower than plain sprites. Only the first two rows of the matrix is useful, which is why there's only six transform values. These are in signed 8.8 fixed point format. +Affine sprites apply a 3x3 matrix transform. These are slower than +plain sprites. Only the first two rows of the matrix is useful, which +is why there's only six transform values. These are in signed 8.8 +fixed point format. .. code-block:: C @@ -425,7 +487,8 @@ Sprite image data is an array of 16 bit colors. Control Channel $F ------------------ -These registers are managed by the RIA. Do not distribute applications that set these. +These registers are managed by the RIA. Do not distribute applications +that set these. .. list-table:: :widths: 5 5 90 @@ -436,49 +499,71 @@ These registers are managed by the RIA. Do not distribute applications that set - Description * - $1:F:00 - DISPLAY - - This sets the aspect ratio of your display. This also resets CANVAS to the console. - * 0 - VGA (4:3) 640x480 - * 1 - HD (16:9) 640x480 and 1280x720 - * 2 - SXGA (5:4) 1280x1024 + - This sets the aspect ratio of your display. This also resets + CANVAS to the console. + + * 0 - VGA (4:3) 640x480 + * 1 - HD (16:9) 640x480 and 1280x720 + * 2 - SXGA (5:4) 1280x1024 + * - $1:F:01 - - CODEPAGE + - CODE_PAGE - Set code page for built-in font. * - $1:F:02 - UART - - Set baud rate. Reserved, not implemented. + - Set bit rate. Reserved, not implemented. * - $1:F:03 - UART_TX - Alternate path for UART Tx when using backchannel. * - $1:F:04 - BACKCHAN - Control using UART Tx as backchannel. - * 0 - Disable - * 1 - Enable - * 2 - Request acknowledgment + + * 0 - Disable + * 1 - Enable + * 2 - Request -3. Backchannel -============== +Backchannel +=========== -Because the PIX bus is unidirectional, it can't be used for sending data from the VGA system back to the RIA. Using the UART Rx path is undesirable since there would be framing overhead or unusable control characters. Since there is a lot of unused bandwidth on the PIX bus, which is only used when the 6502 is writing to XRAM, it can be used for the UART Tx path allowing the UART Tx pin to switch directions. +Because the PIX bus is unidirectional, it can't be used for sending +data from the VGA system back to the RIA. Using the UART Rx path is +undesirable since there would be framing overhead or unusable control +characters. Since there is a lot of unused bandwidth on the PIX bus, +which is only used when the 6502 is writing to XRAM, it can be used +for the UART Tx path allowing the UART Tx pin to switch directions. -This is not interesting to the 6502 programmer as it happens automatically. RIA Kernel developers can extend its usefulness. The backchannel is simply a UART implemented in PIO so it sends 8-bit values. +This is not interesting to the 6502 programmer as it happens +automatically. It is documented mainly for the hardware explorers +who might be probing UART Tx. -Values 0x00 to 0x7F are used to send a version string as ASCII terminated with a 0x0D or 0x0A. This must be sent immediately after the backchannel enable message is received for it to be displayed as part of the boot message. It may be updated any time after that and inspected with the STATUS CLI command, but currently there is no reason to do so. +Values 0x00 to 0x7F are used to send a version string as ASCII +terminated with a 0x0D or 0x0A. This must be sent immediately after +the backchannel enable message is received for it to be displayed as +part of the boot message. It may be updated any time after that and +inspected with the ``status`` monitor command, but currently there is +no reason to do so. -When bit 0x80 is set, the 0x70 bits indicate the command type, and the 0x0F bits are a scalar for the command. +When bit 0x80 is set, the 0x70 bits indicate the command type, and the +0x0F bits are a scalar for the command. -0x80 VSYNC - The scalar will increment and be used for the LSB of the RIA_VSYNC register. +0x80 VSYNC - The scalar will increment and be used for the LSB of the +RIA_VSYNC register. -0x90 OP_ACK - Some XREG locations are triggers for remote calls which may fail or take time to complete. This acknowledges a successful completion. +0x90 OP_ACK - Some XREG locations are triggers for remote calls which +may fail or take time to complete. This acknowledges a successful +completion. 0xA0 OP_NAK - This acknowledges a failure. -4. Terminal -=========== +Terminal +======== -The RP6502 VGA system includes a color ANSI terminal attached to stdout. +The RP6502 VGA system includes a color ANSI terminal attached as the +console. This terminal does not require flow control to keep up with +115200 bps. C0 control codes ---------------- @@ -554,7 +639,9 @@ Fe Escape Sequences CSI Sequences ------------- -Missing numbers are treated as 0. Some functions, like cursor movement, treat 0 as 1 to be useful without parameters. + +Missing numbers are treated as 0. Some functions, like cursor +movement, treat 0 as 1 to be useful without parameters. .. list-table:: :widths: 15 5 5 75 @@ -591,14 +678,17 @@ Missing numbers are treated as 0. Some functions, like cursor movement, treat 0 * - CSI n J - ED - Erase in Display - - - 0: Erases from the cursor position to the end of the screen. - - 1: Erases from the beginning of the screen to the cursor position. + - - 0: Erases from the cursor position to the end of the + screen. + - 1: Erases from the beginning of the screen to the cursor + position. - 2, 3: Erases the entire screen. * - CSI n K - EL - Erase in Line - - 0: Erases from the cursor position to the end of the line. - - 1: Erases from the beginning of the line to the cursor position. + - 1: Erases from the beginning of the line to the cursor + position. - 2: Erases the entire line. * - CSI n m - SGR @@ -607,7 +697,8 @@ Missing numbers are treated as 0. Some functions, like cursor movement, treat 0 * - CSI 6n - DSR - Device Status Report - - Responds with the cursor position (CPR) ESC\[n;mR, where n is the row and m is the column. 1-indexed. + - Responds with the cursor position (CPR) ESC\[n;mR, where n is + the row and m is the column. 1-indexed. * - CSI s - SCP - Save Current Cursor Position @@ -620,7 +711,8 @@ Missing numbers are treated as 0. Some functions, like cursor movement, treat 0 SGR Parameters -------------- -Multiple parameters may be sent separated by semicolons. Reset is performed if no codes (CSI m). +Multiple parameters may be sent separated by semicolons. Reset is +performed if no codes (CSI m). .. list-table:: :widths: 10 20 70 @@ -638,6 +730,7 @@ Multiple parameters may be sent separated by semicolons. Reset is performed if n * - 5 - Blink - Some ANSI art uses this to brighten the background color. + It's a quirk of ANSI.SYS on IBM VGA. * - 22 - Normal intensity - Normal foreground colors. Colors 8-15 dimmed.