TS-4100 ZPU

From embeddedTS Manuals

The on-board FPGA contains a ZPU core.

The ZPU is a 32-bit stack based CPU with a full gcc compiler available for it. Our specific implementation gives it a single length of contiguous FPGA BlockRAM for code and data storage. The ZPU can be used to offload processing tasks, perform real-time operations, or facilitate communication between the ZPU and external peripherals. The ZPU is controlled completely from userspace using the 'tszpuctl' utility. This utility can load binaries, compile and load from source code, control reset of the ZPU, dump the entire memory space, or connect stdin and stdout from the terminal to the ZPU.

The ZPU has a total of 8192 bytes of RAM for shared code, data, and stack space. After exiting from reset, it begins execution from the lowest address with the stack starting from the highest address of RAM. The entire RAM address space is accessible through the FPGA interface. This is how applications are loaded in to the ZPU. It is also used for the communication FIFO and can be used as a way to quickly extract the entire contents of the ZPU for debugging or other purposes.


ZPU FIFO

A RAM based communication channel can be created to facilitate data transmission between the running ZPU and the main CPU. This channel is agnostic of the connection between the FPGA and the CPU. So long as the CPU can read and write any arbitrary address in the ZPU memory space, this channel is available. It is a bidirectional communication channel for arbitrary data between the ZPU and CPU.

The FIFO is implemented in software. There is an API for code running on the ZPU as well as a separate API for userspace software running on the CPU.

The ZPU reserves 256 bytes for TX and 16 bytes for RX at runtime in a structure. The base of this structure is placed at a known memory location. The CPU can then read from this memory location which contains the size of each FIFO, the head and tail of each FIFO, and other options for the FIFO.

When the ZPU needs to send data to the CPU it writes the bytes to the next free TXFIFO entries, updates the TXFIFO head pointer, and then raises the IRQ to the CPU. In order to assert an IRQ, the ZPU writes an address to the IRQ register. The IRQ remains asserted until the CPU reads from the address written to the IRQ register, or the ZPU is reset. For this reason, the FIFO implementation writes the address of the current TXFIFO head to the IRQ register. Once the CPU reads from the head address, the IRQ will deassert. The CPU sees the interrupt, reads from the current tail through the head of the TXFIFO, and then updates the new tail address when completed. There is an option for "flow control" which will prevent the ZPU from writing additional data to the TXFIFO if it is full.

When the CPU needs to send data to the ZPU, it writes data directly in to the ZPU RXFIFO and then changes the head. The ZPU is required to poll for changes in the head position in its RXFIFO. Once it sees a difference, it reads a byte from the RXFIFO and then changes the tail position.


ZPU Demo

We have included a demo ZPU application that simply shows how the ZPU can interact directly with FPGA I/O, as well as an example of the ZPU FIFO implementation. The ZPU can be loaded and started with one command, and the FIFO can be connected to with another:

tszpuctl --load /usr/local/bin/zpu/zpu_demo.bin
tszpuctl --connect

The 'tszpuctl --connect' connects the ZPU FIFO directly to the terminal's stdin and stdout. The "zpu_demo.bin" application will toggle the red and green LEDs with every character typed, as well as echo every character back. When enter/return is pressed, the ZPU will display the number of timer ticks since the last character the ZPU received. The standard "ctrl+c" escape sequence is used to exit from 'tszpuctl'.


Building ZPU Applications

Note: This section is incomplete at this time


Source code for 'tzpuctl' as well as our ZPU applications and APIs are available in the TS-4100 utilities repository.