URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/s6soc
- from Rev 35 to Rev 36
- ↔ Reverse comparison
Rev 35 → Rev 36
/trunk/doc/spec.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/doc/src/spec.tex
26,6 → 26,7
with this program. If not, see \texttt{http://www.gnu.org/licenses/} for a copy. |
\end{license} |
\begin{revisionhistory} |
0.2 & 5/14/2016 & Gisselquist & Updated Draft, still not complete \\\hline |
0.1 & 4/22/2016 & Gisselquist & First Draft \\\hline |
\end{revisionhistory} |
% Revision History |
50,7 → 51,7
This project comes from my desire to demonstrate the Zip CPU's utility in a |
challenging environment. The CMod~S6 board fits this role nicely. |
\begin{enumerate} |
\item The Spartan--6 LX4 FPGA is very limited in it's resources: |
\item The Spartan--6 LX4 FPGA is very limited in its resources: |
It only has 2,400 look--up tables (LUTs), and can only support |
a 4,096~Word RAM memory (16 kB). |
\item With only 4kW RAM, the majority of any program will need to be placed into |
105,16 → 106,257
and program the flash memory. Both architectures may be loaded into the flash, |
together with the programming code for the Zip CPU. |
|
The basic approach is simple: up and until the software works, the S6 will |
power up into the alternate architecture of Fig.~\ref{fig:altarchitecture}. |
While in this state, the flash may be examined and programmed. Once complete, |
a UART command to the ICAPE port will tell the S6 to load the (primary) |
FPGA configuration from an alternate flash location. This alternate location |
will contain a configuration image containing the CPU. The CPU will then begin |
following the instructions given to it from the flash. |
The basic approach to loading the board is actually quite simple. Using the |
Digilent ADEPT JTAG configuration program, {\tt djtgcfg}, the alternate |
configuration may be written directly to the device. Once this alternate |
configuration has been loaded, the flash may be examined and programmed. |
This includes programming a primary and alternate configuration into the |
configuration section of the flash. Once complete, the system may then be |
reloaded with the primary configuration file which will contain an image of |
the CPU. The CPU will then begin following the instructions found in flash |
memory. |
|
|
\chapter{Software} |
\section{Directory Structure} |
\begin{itemize} |
\item[{\tt trunk/bench}] Contains software for emulating the S6 without the S6 |
present. |
\begin{itemize} |
\item[{\tt trunk/bench/cpp}] All of the bench testing software is |
written in C++, so it is found in this directory. Primary |
among these programs is the {\tt zip\_sim} program which will |
simulate the ZipCPU within the S6--Soc. Specifically, it |
simulates everything at or below the {\tt busmaster.v} level. |
|
Some, although not all, of the peripherals have been simulated |
and made a part of this simulation. These include the |
Quad--SPI flash, the UART, and the LED's. |
|
\end{itemize} |
\item[{\tt trunk/doc}] All of the documentation for the S6SoC project may be |
found in this documentation directory. Specifically, I would commend |
your attention to anything with a {\tt .pdf} extension, as these |
are the completed documents. Among these you should find a copy of the |
GPL copyright under which this software is released, as well as a |
pre--built copy of this document. |
\begin{itemize} |
\item[{\tt trunk/doc/gfx}] Here is where the graphics are located in |
support of this specification document. |
\item[{\tt trunk/doc/src}] And here is where the \LaTeX files are |
kept that were used in building both this document as well as |
the GPL copyright. |
\end{itemize} |
\item[{\tt trunk/rtl}] Verilog files |
\begin{itemize} |
\item[{\tt trunk/rtl/cpu}] Verilog files containing the ZipCPU |
core and peripherals. The toplevel file here is the |
{\tt zipbones.v} file, although some of the peripherals, such |
as the {\tt ziptimer.v} are referenced independently. |
\end{itemize} |
\item[{\tt trunk/sw}] The main software directory, primarily a repository |
for software subdirectories beneath it. |
\begin{itemize} |
\item[{\tt trunk/sw/dev}] This directory holds a variety of |
simple programs for the ZipCPU, such as {\tt helloworld}, |
{\tt doorbell} and {\tt doorbell2}, as well as software drivers |
for various peripherals, such as the real--time clock simulator, |
and the keypad and display device drivers. |
\item[{\tt trunk/sw/host}] This directory holds support software which |
can be built on and run on the host machine. Building this |
software will involve adjusting the Makefile so that it knows |
where your local ADEPT installation directory is.\footnote{Many |
of the programs also depend upon the serial number of my CMod |
S6 device. This will need to be adjusted in any new install.} |
Once built, you will find a variety of very useful programs |
within here. |
\item[{\tt trunk/sw/zipos}] This directory contains the source code for |
a rudimentary, very basic, operating system that I |
call the ZipOS. |
\end{itemize} |
\end{itemize} |
|
\section{ZipCPU Tool Chain} |
To build programs for the ZipCPU, you will need the ZipCPU toolchain. You |
can find this as part of the ZipCPU project, available at OpenCores. Building |
the ZipCPU project should result in a set of binaries in the |
\hbox{\tt trunk/sw/install/cross-tools/bin} directory. Make this directory |
a part of your path, and you should be able to build the CMod S6 ZipCPU |
software. Specifically, you will need to use {\tt zip-gcc}, {\tt zip-as} |
{\tt zip-ld}, and {\tt zip-cpp}. Other tools, such as {\tt zip-objdump} and |
{\tt zip-readelf}, may also prove to be very useful when trying to figure out |
what is going on within the SoC. |
|
\section{Bench Test Software} |
|
Bench testing software currently consists of the {\tt zip\_sim} program found |
within {\tt trunk/bench/cpp}. This program requires Verilator to run, and |
simulates in a cycle accurate fashion, the entire S6SoC from {\tt busmaster.v} |
on down. Further, the external Quad--SPI flash memory, UART, and LED's are |
also simulated, although the 2--line display, audio, and keypad are not. |
|
\section{Host Software} |
These include: |
\begin{itemize} |
\item {\tt dumpuart}: My current approach to debugging involves |
dumping the state of the registers and memory to the |
UART upon reboot. The dumpuart command found here is |
designed to make certain that the UART is first set |
up correctly at 9600~Baud, and that second everything |
read from the UART is directly sent to both a file and |
to the screen. In this fashion, it is similar to the |
UNIX {\tt tee} program, save for its serial port |
attachment. |
\item {\tt readflash}: As I am loathe to remove anything from |
a device that came factory installed, the |
{\tt readflash} program reads the original installed |
configuration from the flash and dumps it to a file. |
\item {\tt wbregs} |
\item {\tt zipload}: This is the primary program you will need |
to get your software loaded on the CMod. It takes three |
arguments. The first is the name of the primary |
Xilinx configuration file, the second is the name |
of the alternate Xilinx configuration file, and the |
third is the name of the ZipCPU program you wish to |
write to Flash memory. |
|
Each of these arguments is optional. For example, if |
only one configuration file is given, the loader will |
load the primary configuration. If only one ZipCPU |
program is given, the program will be loaded into |
the program memory area and the configuration file areas |
will be left untouched. |
\end{itemize} |
\section{ZipCPU Programs} |
\begin{itemize} |
\item {\tt helloworld}: The first program any programmer should build, |
``Hello, world!'' This program sends the string, ``Hello, world!'' |
over the UART connection once per second. It is a very valuable |
program because, if you can get this program running, you know you have |
a lot of things working and working correctly. For example, running |
this program means you can run the {\tt zip-gcc} compiler, load |
the auxiliar configuration, load the program info flash memory, load |
the primary configuration, and read from the UART port. It also means |
that you must have the UART port properly configured and wired to your |
CMod board. |
\item {\tt doorbell}: This annoying program verifies the functionality of the |
audio device by playing a doorbell sound to the audio port. It will |
then wait ten seconds, and play the doorbell sound again (and again, |
and again). (It gets old after a while ...) |
\item {\tt doorbell2}: This adds to the functionality of the {\tt doorbell} |
program a wait for keypress, and a display of the current time on the |
2--line display. While almost our fully functional program, this |
does not include any menus to configure the device or set time, since |
it doesn't include any keypad functionality. |
\item {\tt kptest}: A test of whether or not they keypad driver works. When |
run, anytime a key is pressed, the key's value (in hex) will be |
sent to the UART. Further, pressing an `F' on the keypad will also |
send a newline over the UART, in case you wish to keep your lines from |
getting too long. |
\end{itemize} |
\section{ZipOS} |
This operating system is pre--emptive and multitasking, although with many |
limitations. Those familiar with the internals of the Linux kernel may laugh |
that I call this an Operating System at all: it has no memory management unit, |
no paging, no virtual memory, no file I/O access, no network stack, no ability |
to dynamically add or remove tasks, indeed it hardly has any of the things |
most often associated with an Operating System. It does, however, handle |
interrupts, support multiple pre--emptive tasks in a multitasking, timesharing |
fashion, and it supports some very basic and rudimentary system calls. In a |
similar fashion, it does contain just about all of the functionality necessary |
for a multi--tasking microcontroller built around a do--forever loop. For its |
size, I consider it an impressive achievement. You are welcome to disagree |
with me, however. |
|
This version of the ZipOS starts in the resetdump.s code, so that upon |
any startup the ZipOS will dump register contents, the BusError register, and |
any scope contents to the UART. This can take some time, so you may wish to |
configure what you really wish to send--if anything. If desired, this will |
also dump the entire memory as well. All of this is quite useful in case the |
ZipCPU encounters a bus error or other sort of error that causes it to hang, |
stall, or reboot, as these registers are very carefully not touched prior to |
being sent to the UART output port. |
|
{\tt resetdump.s} also calls a rudimentary bootloader, to load the parts of |
the ZipOS that need to run faster into Block RAM. The choice of what parts |
to load into Block RAM is made on a file by file basis, and found within |
the linker script, {\tt cmodram.ld}. |
|
Upon completion, {\tt resetdump.s} calls the entry routine for the O/S, |
{\tt kernel\_entry()} found in {\tt kernel.c}. This is the main task loop for |
the entire O/S, and worth studying if you are interested in understanding how |
the O/S works. |
|
The user tasks are found (mostly) within {\tt doorbell.c}, also found in the |
ZipOS directory. This file contains two kernel entry points, {\tt kntasks()}, |
which returns the number of tasks the kernel needs to know about, and |
{\tt kinit()}, which builds each of the tasks and connects their file |
descriptors to the various devices they will be referencing. |
\subsection{Traps} |
The ZipCPU supports a variety of traps, listed here: |
\begin{itemize} |
\item WAIT: Halts the execution of a process until an event takes place, or |
a timeout has been reached. The events that can take place are a |
bitmask of the various interrupts the CPU supports, together with a |
bitmask of the values found in {\tt swint.h}. |
|
The timeout value can either be zero, to return immediately with the |
list of events that have taken place, negative, to wait indefinitely, |
or a positive number of milliseconds in order to wait at least that |
time for the event of interest to take place. |
|
This also allows a process to sleep for any number of milliseconds. |
|
When wait returns, any events returned by the wait have been cleared. |
|
The other thing to be aware of is that events may accumulate before the |
wait system call. They will only be returned and cleared, though, if |
the wait call indicates an interest in those events. |
\item CLEAR: This system call works closely with the wait system call. |
Indeed, it is very similar to a wait system call with a zero timeout. |
It clears any of the requested events which may be pending. If given |
a timeout (in milliseconds), it will start a timer and generate a |
{\tt SWINT\_TIMEOUT} event to be sent to this process when the timer |
completes. |
\item POST: Certain devices, such as the real--time clock and the doorbell |
reader, need the ability of being able to post events to any listener |
within the O/S. The POST system call allows them to POST events in |
this manner. |
\item YIELD: This is simply a way of being nice to other processes. This system |
call takes no arguments and simply asks the scheduler to schedule the |
next process. It does not take this process off of the ready to run |
list, so the next process may be this one. However, since the scheduler |
is a round--robin scheduler, it will only return to this process if |
nothing else is available to run. |
\item READ: This is roughly the same system call as the POSIX read() system |
call. It reads some number of memory addresses (words, not octets), |
to the given file descriptor. If the memory requested is unavailable, |
the read will wait until it is available, possibly indefinitely. |
\item WRITE: This is roughly the same system call as the POSIX write() system |
call. It writes some number of memory addresses (words, not octets), |
to the given file descriptor. If nothing is reading from the device, |
the write stall the task forever, otherwise it will only stall the task |
until the data is either written to the receiving task, or copied into |
a memory buffer. |
\item TIME: Returns the number of seconds since startup. Eventually, this will |
return the number of seconds since January 1, 1970, and be identical |
to the UNIX system time() command, but that may not happen on this |
project. |
% \item SEMGET |
% \item SEMPUT |
\item MALLOC: Allocates memory from the system/kernel heap. This is a very |
low overhead memory allocator that, while it does allocate memory, |
cannot free it later. It is nearly 100\% efficient since only |
one memory address, the top of the heap, is used to determine what |
memory has been allocated. |
\item FREE: Not currently implemented. |
\end{itemize} |
\subsection{Scheduler} |
The ZipCPU currently supports only a round--robin scheduler. Tasks are executed |
in the order they were created, as long as they are available to be executed. |
If no tasks are available to be run, the Scheduler will run the idle task which |
puts the CPU to sleep while waiting for an interrupt. |
|
\chapter{Operation} |
|
\chapter{Registers} |
141,43 → 383,7
from the debugging scope device's data port will read a word from the scope's |
buffer and advance the buffer pointer. |
|
\section{Debugging Scope} |
The debugging scope consists of two registers, a control register and a data |
register. It needs to be internally wired to 32--wires, internal to the S6 |
SoC, that will be of interest later. For further details on how to configure |
and use this scope, please see the {\tt WBSCOPE} project on OpenCores. |
|
\section{Internal Configuration Access Port} |
The Internal Configuration Access Port (ICAP) provides access to the internal |
configuration details of the FPGA. This access was designed so as to provide |
the CPU with the capability to command a different FPGA load. In particular, |
the code in Fig.~\ref{fig:reload} should reconfigure the FPGA from any given |
Quad SPI {\tt address}.\footnote{According to Xilinx's technical support, this |
will only work if the JTAG port is not busy.} |
\begin{figure}\begin{center}\begin{tabbing} |
{\tt warmboot(uint32 address) \{} \\ |
\hbox to 0.25in{}\={\tt uint32\_t *icape6 = (volatile uint32\_t *)0x{\em <ICAPE port address>};}\\ |
\>{\tt icape6[13] = (address<<2)\&0x0ffff;}\\ |
\>{\tt icape6[14] = ((address>>14)\&0x0ff)|((0x03)<<8);}\\ |
\>{\tt icape6[4] = 14;}\\ |
\>{\em // The CMod~S6 is now reconfiguring itself from the new address.}\\ |
\>{\em // If all goes well, this routine will never return.}\\ |
{\tt \}} |
\end{tabbing} |
\caption{Spartan--6 ICAPE Usage}\label{fig:reload} |
\end{center}\end{figure} |
|
For further details, please see either the {\tt WBICAPETWO} project on OpenCores |
as well as Xilinx's ``Spartan-6 FPGA Configuration User Guide''. |
|
\section{Real--Time Clock} |
The Real Time Clock will be included if there is enough area to support it. |
The four registers correspond to a clock, a timer, a stopwatch, and an alarm. |
If space is tight, the timer and stopwatch, or indeed the entire clock, may be |
removed from the design. For further details regarding how to set and use this |
clock, please see the {\tt RTCCLOCK} project on OpenCores. |
|
\section{I/O Peripherals} |
\section{Peripheral I/O Control} |
Tbl.~\ref{tbl:ioregs} |
\begin{table}[htbp] |
\begin{center}\begin{reglist} |
186,7 → 392,7
TIMA &\scalebox{0.8}{\tt 0x0102} & 32 & R/W & ZipTimer A\\\hline |
TIMB &\scalebox{0.8}{\tt 0x0103} & 32 & R/W & ZipTimer B\\\hline |
PWM &\scalebox{0.8}{\tt 0x0104} & 32 & R/W & PWM Audio Controller\\\hline |
KYPAD &\scalebox{0.8}{\tt 0x0105} & 32 & R/W & Special Purpose I/O, Keypad, LED Controller \\\hline |
SPIO &\scalebox{0.8}{\tt 0x0105} & 32 & R/W & Special Purpose I/O, Keypad, LED Controller \\\hline |
GPIO &\scalebox{0.8}{\tt 0x0106} & 32 & R/W & GPIO Controller \\\hline |
UART &\scalebox{0.8}{\tt 0x0107} & 32 & R/W & UART data\\\hline |
\end{reglist} |
194,24 → 400,130
\end{center}\end{table} |
shows the addresses of various I/O peripherals included as part of the SoC. |
|
\subsection{Interrupt Controller} |
The interrupt controller is identical to the one found with the ZipSystem. |
Please read the ZipSystem documentation for how to control this. |
The layout of the PIC bits is shown in Fig.~\ref{fig:picreg}. |
\begin{figure}\begin{center} |
\begin{bytefield}[endianness=big]{32} |
\bitheader{0-31} \\ |
\bitbox{1}{E} |
\bitbox{15}{Enabled} |
\bitbox{1}{A} |
\bitbox{15}{ACTIVE} |
\\ |
\end{bytefield} |
\caption{Programmable Interrupt Control (PIC) Register}\label{fig:picreg} |
\end{center}\end{figure} |
This controller supports up to fifteen interrupts, however only twelve are |
defined within the SoC. If any interrupt line is active, the PIC controller |
will have that bit set among it's active set. Once set, the bit and hence the |
interrupt can only be cleared by writing to the controller. Interrupts can |
also be enabled as well. The enabled bit mask controls which interrupt lines |
are permitted to interrupt the CPU. Hence, just because an interrupt is active |
doesn't mean it will interrupt the CPU--the enabled line must be set as well. |
Finally, then {\tt A} or {\tt ANY} bit will be high if any interrupts are both |
enabled and active, whereas the {\tt E} or global interrupt enable bit can be |
set to allow the PIC to interrupt the CPU or cleared to disable all interrupts. |
|
To keep operations on this register atomic, most of the bits of this register |
have special meanings upon write. The one exception to this is the global |
interrupt enable bit. On any write, interrupts will be globally enabled or |
disabled based upon the value of this bit. Further, the {\tt ANY} bit is a |
read only bit, so writes to it have no effect. |
|
Enabling specific interrupts, via writes to the enable lines, are different. |
To enable a specific interrupt, enable all interrupts and |
set the wire high associated with the specific interrupt you wish to enable. |
Hence writing a {\tt 0x80010000} will enable interrupt line zero, while also |
enabling all previously enabled interrupts. |
To disable a specific interrupt, disable all interrupts and write a one to the |
enable line of the interrupt you wish to disable. In this fashion, writing a |
{\tt 0x00010000} will disable all interrupts and leave interrupt line zero |
disabled when the interrupts are re--enabled later, whereas {\tt 0x07fff0000} |
will disable all specific interrupts. |
|
Interrupts are acknowledged in a fashion similar to enabling interrupts. By |
writing a `1' to the active bit mask, the interrupt will be acknowledged and |
reset, whereas writing a `0' leaves the interrupt untouched. In this fashion, |
as individual interrupts are handled, a `1' may be written to this bottom mask |
to clear the interrupt. Be aware, however, that any interrupt acknowledgement |
may also globally enable or disable interrupts. |
|
\subsection{Last Bus Error Address} |
The Bus Error peripheral simply records the address of the last bus error. |
This can be useful when debugging. While the peripheral may only be read, |
setting it is really as easy as creating a bus error and trapping the result. |
Another use for this is upon any reboot, it is possible to read the address |
of the last bus error and perhaps learn something of what caused the CPU to |
restart. |
|
The two ZipTimer's are ZipSystem timer's, placed onto this peripheral bus. |
They are available for the CPU to use. Common uses might include I2C or SPI |
speed control, or multi--tasking task-swap control. For further details, please |
see the ZipSystem documentation. |
\subsection{ZipTimer} |
The S6 Soc contains two ZipTimers, available for the CPU to use. These are |
countdown timers. Writing any non--zero value to them will cause them to |
immediately start counting down from that value towards zero, and to interrupt |
the CPU when they reach zero. Writing a new value while the timer is running |
will cause that new value to automatically load into the CPU and start counting |
from there. Writing a zero to the timer disables the timer, and causes it to |
stop. |
|
Audio Controller |
ZipTimer A can be set to auto reload. When set, the timer will automatically |
load it's last set value upon reaching zero and interrupting the CPU. This |
effectively turns it into an interrupt timer if desired. To set this feature, |
write to the timer the number of clock ticks before an interrupt, but also set |
the high order bit. In this fashion, writing a {\tt 0x80013880} will interrupt |
the CPU every millisecond, starting one millisecond after the write takes place |
(assuming an 80~MHz system clock). |
|
Register {\tt KYPAD}, as shown in Fig.~\ref{fig:spioreg}, |
ZipTimer B has been wired for a different purpose. ZipTimer B does not support |
auto reload, nor will it interrupt the CPU. Instead, ZipTimer B has been wired |
as a watchdog timer. When this timer reaches zero, the CPU will be rebooted. |
One way to use this timer would be in conjunction with the ZipTimer A, and to |
write a number to it upon any entry to the interrupt service routine. If given |
enough time, this would cause the CPU to reboot if for any reason it locked up. |
|
\subsection{PWM Audio Controller} |
The bit fields of the PWM Audio controller are shown in Fig.~\ref{fig:pwmreg}. |
\begin{figure}\begin{center} |
\begin{bytefield}[endianness=big]{32} |
\bitheader{0-31} \\ |
\bitbox{10}{Unused} |
\bitbox{1}{S} |
\bitbox{1}{G} |
\bitbox{3}{} |
\bitbox{1}{E} |
\bitbox{16}{Sample} |
\\ |
\end{bytefield} |
\caption{PWM Audio Controller Bitfields}\label{fig:pwmreg} |
\end{center}\end{figure} |
This controller has been designed for easy writing. To send a sample to the |
PWM audio controller, simply write the sample to the controller and clear the |
PWM audio interrupt. When the audio interrupts the CPU again, it is ready |
for the next sample. |
|
The audio sample rate has been fixed at 8~kHz. While changing this rate is |
easy to do within {\tt busmaster.v}, the rate itself takes some work to keep |
up with, so I wouldn't recommend going much (any) faster. |
|
The audio controller supports two additional functionalities, however. The |
first is that the {\tt E} bit will be set upon any read when or if the audio |
controller is ready for another sample. Equivalently, the audio interrupt |
will be asserted. |
|
The second functionality has to do with the two auxiliary control bits present |
in the PModAMP2 audio device. These are the gain and shutdown bits. To set |
these bits, write a sample to the controller while also setting the {\tt E} |
bit. When the {\tt E} bit is set upon any write, the shutdown and gain bits |
will also be set. (Be aware, the shutdown bit is negative logic.) Hence, one |
may start this interface by writing a {\tt 0x0310000} to the device, and later |
shut it back off by writing a {\tt 0x010000}. |
|
\subsection{Special Purpose I/O} |
|
Register {\tt SPIO}, as shown in Fig.~\ref{fig:spioreg}, |
\begin{figure}\begin{center} |
\begin{bytefield}[endianness=big]{32} |
\bitheader{0-31} \\ |
\begin{leftwordgroup}{Read}\bitbox[lrt]{16}{Zeros} |
\bitbox[lrt]{4}{Kpad} |
\bitbox[lrt]{4}{Kpad} |
247,9 → 559,16
output, a `1' needs to be written to the change enable bit in order for a |
new value to be accepted. |
|
As examples, writing a {\tt 0x0ff} to the {\tt SPIO} register will turn all |
LED's on, {\tt 0x0f0} will turn all LED's off, and {\tt 0x011} and {\tt 0x010} |
will turn LED0 on and then off again respectively. |
|
The controller will generate a keypad interrupt whenever any row input is |
zero, and a button interrupt whenever any button value is a one. |
zero, and a button interrupt whenever any button value is a one. This also |
means that, once generated, the interrupt must be disabled until the key or |
button is released. |
|
\subsection{General Purpose I/O} |
The General Purpose Input and Output (GPIO) control register, shown in |
Fig.~\ref{fig:gpioreg}, |
\begin{figure}\begin{center} |
263,7 → 582,7
is quite simple to use: when read, the top 16--bits indicate |
the value of the 16--input GPIO pins, whereas the bottom 16--bits indicate |
the value being placed on the 16--output GPIO pins. To change a GPIO pin, |
write the new pins value to this register, together with setting the |
write the new pin's value to this register, together with setting the |
corresponding pin in the upper 16--bits. For example, to set output pin 0, |
write a {\tt 0x010001} to the GPIO device. To clear output pin 0, write a |
{\tt 0x010000}. This makes it possible to adjust some output pins independent |
271,27 → 590,118
|
The GPIO controller, like the keypad or SPIO controller, will also generate |
an interrupt. The GPIO interrupt is generated whenever a GPIO input line |
changes. |
changes. The interrupt is not selective: if any line changes, a GPIO interrupt |
will be generated. There are no do not care lines. |
|
Of the 16 GPIO inputs and the 16 GPIO outputs, two lines have been taken for |
I2C support. GPIO line zero, for both input and output, is an I2C data line, |
and GPIO line one is an I2C clock line. If the output of either of these |
{\tt io\_sda}, and GPIO line one is an I2C clock line, {\tt io\_scl}. If the |
output of either of these |
lines is set to zero, the GPIO controller will drive the line. Otherwise, |
the line is pulled up with a weak resistor so that other devices may |
pull it low. If either line is low, when the output control bit is high, |
it is an indicator that another device is sending data across these wires. |
|
\subsection{UART Data Register} |
Moving on to the UART \ldots |
although the UART module within the S6~SoC is highly configurable, as built |
the UART can only handle 9600~Baud, 8--data bits, no parity, and one stop bit. |
There is a single byte data buffer, so reading from the port has a real--time |
requirement associated with it. |
Changing this involves changing the constant {\tt uart\_setup} within |
{\tt busmaster.v}. Further, the UART has only a single byte data buffer, so |
reading from the port has a real--time requirement associated with it--the |
data buffer must be emptied before the next value is read. |
Attempts to read from this port will either return an 8--bit data value from |
the port, or if no values are available it will return an {\tt 0x0100} |
indicating that fact. In a similar fashion, writes to this port will send |
the lower 8--bits of the write out the serial port. If the port is already |
busy, a single byte will be buffered. |
indicating that fact. In general, reading from the UART port involves first |
waiting for the interrupt to be ready, second reading from the port itself, |
and then third immediately clearing the interrupt. (The interrupt cannot |
be cleared while data is waiting.) Writing to the UART port is done in a |
similar fashion. First, wait until the UART transmit interrupt is asserted, |
second write to the UART port, and then third clear the interrupt. As with |
the read interrupt, clearing the interrupt prior to writing to the port will |
have no effect. |
|
\section{Debugging Scope} |
The debugging scope consists of two registers, a control register and a data |
register. It needs to be internally wired to 32--wires, internal to the S6 |
SoC, that will be of interest later. For further details on how to configure |
and use this scope, please see the {\tt WBSCOPE} project on OpenCores. |
|
\section{Internal Configuration Access Port} |
The Internal Configuration Access Port (ICAP) provides access to the internal |
configuration details of the FPGA. This access was designed so as to provide |
the CPU with the capability to command a different FPGA load. In particular, |
the code in Fig.~\ref{fig:reload} should reconfigure the FPGA from any given |
Quad SPI {\tt address}.\footnote{According to Xilinx's technical support, this |
will only work if the JTAG port is not busy.} |
\begin{figure}\begin{center}\begin{tabbing} |
{\tt warmboot(uint32 address) \{} \\ |
\hbox to 0.25in{}\={\tt uint32\_t *icape6 = (volatile uint32\_t *)0x{\em <ICAPE port address>};}\\ |
\>{\tt icape6[13] = (address<<2)\&0x0ffff;}\\ |
\>{\tt icape6[14] = ((address>>14)\&0x0ff)|((0x03)<<8);}\\ |
\>{\tt icape6[4] = 14;}\\ |
\>{\em // The CMod~S6 is now reconfiguring itself from the new address.}\\ |
\>{\em // If all goes well, this routine will never return.}\\ |
{\tt \}} |
\end{tabbing} |
\caption{Spartan--6 ICAPE Usage}\label{fig:reload} |
\end{center}\end{figure} |
|
One subtle problem with this port is that it will not work if the CMod is |
plugged in to the USB JTAG port. It will only work if the CMod has been |
provided with an independent power supply, leaving the USB JTAG unplugged. |
|
For further details, please see either the {\tt WBICAPETWO} project on OpenCores |
as well as Xilinx's ``Spartan-6 FPGA Configuration User Guide''. |
|
\section{Real--Time Clock} |
The Real Time Clock will be included if there is enough area to support it. |
The four registers correspond to a clock, a timer, a stopwatch, and an alarm. |
If space is tight, the timer and stopwatch, or indeed the entire clock, may be |
removed from the design. For further details regarding how to set and use this |
clock, please see the {\tt RTCCLOCK} project on OpenCores. |
|
There is currently not enough area on the chip to support the Real--Time Clock |
together with all of the other peripherals listed here. You can adjust whether |
the clock is included or not by adjusting the {\tt `define} lines at the top |
of {\tt busmaster.v}. For example, it may be possible to get the RTC back by |
disabling the ICAPE2 interface. |
|
\section{On-Chip Block RAM} |
|
The block RAM is the fastest memory available to the processor. It is also |
the {\em only} writeable memory available to the processor. Hence all |
non-constant program data {\em must} be placed into block RAM. The ZipCPU |
can also run instructions from the block RAM if extra speed is desired. When |
runnning from block RAM, the ZipCPU will nominally take 8~clocks per |
instruction, for an effective rate of 8~MIPS. Loads or stores to block RAM |
will take one instruction longer. |
|
\section{Flash Memory} |
The flash memory has been arbitrarily sectioned into three sections, one for |
a primary configuration, a second section for an alternate configuration file, |
and the third section for any program and data. These regions are shown in |
Tbl.~\ref{tbl:flash-addresses}. |
\begin{table}[htbp] |
\begin{center}\begin{tabular}{|p{0.75in}|p{0.75in}|p{0.5in}|p{3.0in}|}\hline |
\rowcolor[gray]{0.85} Start & End & & Purpose \\\hline\hline |
\scalebox{0.9}{\tt 0x400000} & \scalebox{0.9}{\tt 0x43ffff} & R & Primary configuration space\\\hline |
\scalebox{0.9}{\tt 0x440000} & \scalebox{0.9}{\tt 0x47ffff} & R & Alternate configuration space\\\hline |
\scalebox{0.9}{\tt 0x480000} & \scalebox{0.9}{\tt 0x7fffff} & R & ZipCPU program memory\\\hline |
\end{tabular} |
\caption{Flash Address Regions}\label{tbl:flash-addresses} |
\end{center}\end{table} |
The host program {\tt zipload} can be used to load a ZipCPU program and |
configuration files into this address space. To use it, first load the |
alternate configuration into the FPGA. Then pass it, as arguments, the |
primary, and alternate if desired, configuration files followed by the ZipCPU |
program file. Then, when the primary configuration is loaded again, perhaps |
upon power up, the ZipCPU will automatically start running from it's |
{\tt RESET\_ADDRESS}, {\tt 0x480000}. |
|
When running from Flash memory, the ZipCPU will nominally take 52~clocks per |
instruction, for an effective speed of about 1.5~MIPS. |
|
\chapter{Clocks} |
|
The S6~SoC is designed to run off of one master clock. This clock is derived |