URL
https://opencores.org/ocsvn/openarty/openarty/trunk
Subversion Repositories openarty
Compare Revisions
- This comparison shows the changes necessary to convert path
/openarty/trunk
- from Rev 35 to Rev 36
- ↔ Reverse comparison
Rev 35 → Rev 36
/Makefile
40,9 → 40,10
BENCH := `find bench -name Makefile` `find bench -name "*.cpp"` `find bench -name "*.h"` |
RTL := `find rtl -name "*.v"` `find rtl -name Makefile` |
NOTES := `find . -name "*.txt"` `find . -name "*.html"` |
SW := `find sw -name "*.cpp"` `find sw -name "*.h"` \ |
`find sw -name "*.sh"` `find sw -name "*.py"` \ |
`find sw -name "*.pl"` `find sw -name Makefile` |
SW := `find sw -name "*.cpp"` `find sw -name "*.c"` \ |
`find sw -name "*.h"` `find sw -name "*.sh"` \ |
`find sw -name "*.py"` `find sw -name "*.pl"` \ |
`find sw -name "*.png"` `find sw -name Makefile` |
DEVSW := `find sw-board -name "*.cpp"` `find sw-board -name "*.h"` \ |
`find sw-board -name Makefile` |
PROJ := |
/bench/cpp/fastmaster_tb.cpp
177,7 → 177,7
|
PIPECMDR::tick(); |
|
#define DEBUGGING_OUTPUT |
// #define DEBUGGING_OUTPUT |
#ifdef DEBUGGING_OUTPUT |
bool writeout = false; |
|
225,7 → 225,10
if (m_core->v__DOT__rgbctrl__DOT__dev_busy) |
writeout = true; |
|
if (m_core->v__DOT__zippy__DOT__dma_controller__DOT__dma_state != 0) |
writeout = true; |
|
|
/* |
if (m_core->v__DOT__ppsck__DOT__err_tick) |
writeout = true; |
675,7 → 678,47
(m_core->v__DOT__rgbctrl__DOT__dev_busy)?"D-BSY":" ", |
m_core->v__DOT__rgbctrl__DOT__r_len, |
m_core->v__DOT__rgbctrl__DOT__dev_len); |
printf((m_core->v__DOT__oled_int)?"I":" "); // And the interrupt |
|
// Debug the DMA |
printf(" DMAC[%d]: %08x/%08x/%08x(%03x)%d%d%d%d -- (%d,%d,%c)%c%c:@%08x-[%4d,%4d/%4d,%4d-#%4d]%08x", |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__dma_state, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_waddr, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_raddr, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_len, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_blocklen_sub_one, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__last_read_request, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__last_read_ack, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__last_write_request, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__last_write_ack, |
m_core->v__DOT__zippy__DOT__dc_cyc, |
// m_core->v__DOT__zippy__DOT__dc_stb, |
(m_core->v__DOT__zippy__DOT__dma_controller__DOT__dma_state == 2)?1:0, |
|
((m_core->v__DOT__zippy__DOT__dma_controller__DOT__dma_state == 4) |
||(m_core->v__DOT__zippy__DOT__dma_controller__DOT__dma_state == 5) |
||(m_core->v__DOT__zippy__DOT__dma_controller__DOT__dma_state == 6))?'W':'R', |
//(m_core->v__DOT__zippy__DOT__dc_we)?'W':'R', |
(m_core->v__DOT__zippy__DOT__dc_ack)?'A':' ', |
(m_core->v__DOT__zippy__DOT__dc_stall)?'S':' ', |
m_core->v__DOT__zippy__DOT__dc_addr, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__rdaddr, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__nread, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__nracks, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__nwacks, |
m_core->v__DOT__zippy__DOT__dma_controller__DOT__nwritten, |
m_core->v__DOT__zippy__DOT__dc_data); |
printf((m_core->v__DOT__zippy__DOT__dma_controller__DOT__trigger)?"T":" "); |
printf((m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_incs)?"+":"."); |
printf((m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_incd)?"+":"."); |
printf("%s[%2x]", |
(m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_on_dev_trigger)?"!":" ", |
(m_core->v__DOT__zippy__DOT__dma_controller__DOT__cfg_dev_trigger)); |
|
printf(" INT:0x%08x/0x%08x", |
m_core->v__DOT__zippy__DOT__main_int_vector, |
m_core->v__DOT__zippy__DOT__alt_int_vector); |
|
printf("\n"); fflush(stdout); |
} m_last_writeout = writeout; |
#endif |
/doc/spec.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/doc/src/spec.tex
63,7 → 63,8
with this program. If not, see \texttt{http://www.gnu.org/licenses/} for a copy. |
\end{license} |
\begin{revisionhistory} |
0.0 & 6/20/2016 & Gisselquist & First Draft \\\hline |
0.0 & 6/20/2016 & Gisselquist & First Draft \\\hline |
0.0 & 10/21/2016 & Gisselquist & More Comments Added\\\hline |
\end{revisionhistory} |
% Revision History |
% Table of Contents, named Contents |
73,7 → 74,7
\begin{preface} |
\end{preface} |
|
\chapter{Introduction} |
\chapter{Introduction}\label{ch:intro} |
\pagenumbering{arabic} |
\setcounter{page}{1} |
|
120,15 → 121,336
|
I intend to demonstrate this project with a couple programs: |
\begin{enumerate} |
\item A very simple program that runs automatically upon startup that can be |
used to select from among multiple configurations. |
\item NTP Server |
\item A ZipOS that can actually load and run programs from the SD Card |
|
This will require a functioning memory management unit (MMU), which |
will be a new addition to the ZipCPU created to support this project. |
For those not familiar with MMU's, an MMU translates memory addresses |
from a virtual address space to a physical address space. This allows |
every program running on the ZipCPU to believe that they own the entire |
memory address space, while allowing the operating system to allocate |
actual physical memory addresses as necessary to support whatever |
program needs more (or less) memory. |
\end{enumerate} |
|
\chapter{Architecture} |
|
|
|
|
\chapter{Architecture}\label{ch:architecture} |
My philosophy in peripherals is to keep them simple. If there is a default |
mode on the peripheral, setting that mode should not require turning any bits |
on. If a peripheral encounters an error condition, a bit may be turned on to |
indicate this fact, otherwise status bits will be left in the off position. |
|
\subsection{Bus Structure} |
The OpenArty project contains four bus masters, three of them within the CPU. |
These masters are the instruction fetch unit, the data read/write unit, |
and the direct memory access peripheral within the ZipCPU, as well as an |
external debug port which can be commanded from over the main UART port |
connecting the Arty to its host. |
|
There is also a second minor peripheral bus located within the ZipCPU |
ZipSystem. This bus provides access to a number of peripherals within the |
ZipSystem, such as timers, counters, and the direct memory access controller. |
This bus will also be used to configure the memory management unit once |
integrated. This bus is only visible to the CPU, and located starting at |
address {\tt 0xc0000000}. |
|
The ZipCPU debug port is also available on the bus. This port, however, is |
only visible to the external debug port. It can be found at address |
{\tt 0x08000000} for the control register, and {\tt 0x08000001} for the |
data register. |
|
Once the MMU has been integrated, it will be placed between the instruction |
fetch unit, data read/write unit, and the rest of the peripheral bus. |
|
The actual bus chosen for this design is the Wishbone Bus, based upon the |
pipeline mode defined in the B4 specification. All optional wires required |
by this bus structure have been removed, such as the tag lines, the cycle |
type identifier, the burst type, and so forth. This was done to simplify |
the logic within the core. |
|
However, because of the complicated bus structure--particularly because of the |
number of masters and slaves on the bus and the speed for which the bus is |
defined, there are a number of delays and arbiters placed on the bus. As a |
result, the stall wire which is supposed to be depend upon combinational logic |
only, has been registered at a number of locations. What this means is that |
there are a variety of delays as commands propagate through the bus structure. |
Most of these are variable, in that they can be turned on or off at build time, |
or even that the stall line may (or may not) be registered as configured. |
|
All interactions between bus masters and any peripherals passes through the |
interconnect, located in {\tt busmaster.v}. This interconnect divides the |
slaves into separate groups. The first group of slaves are those for which the |
bus is supposed to provide fast access to. These are the DDR3 SDRAM, the |
flash, the block RAM, and the network. The next group of slaves will have their |
acknowledgements delayed by an additional clock. The final group of slaves |
are those single register slaves whose results may be known ahead of any read, |
and who only require one clock to access. These are grouped together and |
controlled from within {\tt fastio.v}. |
|
Further information about the Wishbone bus structure found within this core |
can be found either on the Wishbone datasheet (Ch.~\ref{ch:wishbone}), or in |
the memory map table in the Registers chapter (Ch.~\ref{ch:registers}). |
|
\subsection{DDR3 SDRAM} |
|
{\em It is the intention of this project to use a completely open source |
DDR3 SDRAM controller. While the controller has been written, it has yet to |
be successfully connected to the physical pins of the port. Until that time, |
the design is running using a Wishbone to AXI bus bridge. Memory may still |
be read or written, after an initial pipeline delay of roughly 27~clocks per |
access, at one access per clock.} |
|
{\em The open source SDRAM controller should be able to achieve a delay closer |
to 9~clocks per access--once I figure out how to connect it to the PHY.} |
|
\subsection{Flash} |
\subsection{Block RAM} |
|
The block RAM on this board has been arranged into one 32kW section. |
Programs that use block RAM will run fastest using the block RAM, both for |
instructions as well as for memory. |
|
\subsection{Ethernet} |
|
The ether net controller has been split into three parts. The first part is |
an area of packet memory. This part is simple: it acts like memory. The |
receive memory is read only, whereas the transmit memory is both read and |
write. Packets received by the controller will be found in the receive memory, |
packets transmitted must be in the transmit area of memory. The octets |
may be found in memory with the first octet in the most significant byte. |
This is the easy part. |
|
The format of the packets within this memory is a touch more interesting. |
With no options turned on, the first 6~bytes are the destination MAC |
address, the next 6~bytes will be the source MAC address, and the {\em next |
4~bytes} will be the EtherType repeated twice. This was done to align the |
packet, and particularly the IP header, onto word boundaries. If the hardware |
CRC has been turned off, the packet must contain its own CRC as well as |
ensuring that it has a minimum packet length (64 octets) when including that |
CRC. |
|
With all options turned on, however, things are a touch simpler. The first |
two words of the packet contain the destination MAC (for a transmit packet) |
or the source MAC (for a received packet), followed by the two--octet |
EtherType. At this point the packet is word--aligned prior to the IP header. |
Since broadcast packets are sent to a special destination MAC other than |
our own, a flag in the command register will indicate this fact. |
|
|
The second part of the controller is the MDIO interface. This follows from |
the specification, and can be used to toggle the LED's on the ethernet, |
to force the ethernet into a particular mode, either 10M or 100M, to control |
auto--negotiation of the speed, and more. Reads or writes to MDIO memory |
addresses will command reads or writes via the MDIO port from the FPGA to the |
ethernet PHY. As the PHY can only handle 16--bit words, only 16~bits will |
ever be transferred as a result of any read/write command, the top 16~bits |
are automatically set to zero. Further details of this capability may be |
found within the specification for the chip. |
|
The MDIO interface may be ignored. If ignored, the defaults within the |
interface will naturally set up the network connection in full duplex mode (if |
your hardware supports it), at the highest speed the network will support. |
However, if you ignore this interface you may not know what problems you are |
suffering from this interface, if any. The {\tt netsetup} program has been |
provided, among the host software, to help diagnose how the various MDIO |
registers have been set, and what the status is that is being reported from |
the PHY. |
|
The third part of the controller is the packet command interface. This |
consists of two command registers, one for reading and one for writing. |
Before doing anything with the network, it must first be taken out of |
reset. According to the specification for the network chip, this must |
happen a minimum of one second after power up. This may be done by simply |
writing to the transmit command register with the reset bit turned off. |
|
To send a packet, simply write the number of octets in the packet to the |
transmit control register and set the GO bit ({\tt 0x04000}). Other bits |
in this control register can be used to turn off the hardware MAC generation |
(and removal upon receive), the hardware CRC checking, and/or the hardware |
IP header checksum validation (but not generation). The GO bit will remain |
high while the packet is being sent, and only transition to low once the |
packet is away. While the packet is being sent, a zero may be written to the |
command register to cancel the packet--although this is not recommended. |
|
Packets are automatically received without intervention. Once a packet has been |
received, the available bit will be set in the receive command register and |
a receive packet interrupt will be generated. The ethernet port will then |
halt/stall until a user has reset the receive interface so that it may |
receive the next packet. Without clearing this interface, the receive port |
will not accept further packets. Other status bits in this interface are |
used to indicate whether packets have been missed (because the interface was |
busy), or thrown out due to some error such as a CRC error or a more general |
error.\footnote{It should be possible to extend this interface so that further |
packets may be read as long as the memory isn't yet full. This is left as an |
exercise to others.} |
|
\subsection{SD Card} |
\subsection{GPS Tracking} |
\subsection{Configuration port} |
|
The registers associated with the ICAPE2 port have been made accessible |
to the core via the {\tt wbicapetwo} core. More information about the meaning |
of these registers can be found in Xilinx's ``7--Series FPGAs Configuration |
User's Guide''. |
|
Testing with the OpenArty board has tended to focus on the warmboot capability. |
Using this capability, a user is able to command the FPGA to reload its |
configuration. In support of this, two configuration areas have been |
defined within memory. The first is the default configuration, found at |
the beginning of the flash. This configuration is sometimes called the ``golden |
configuration'' within Xilinx's documentation because it is the configuration |
that the Xilinx device will always start up from after a power on reset. On |
the OpenArty, a second configuration may immediately follow the first in flash. |
Commanding the FPGA to reload it's configuration is as simple as |
setting the WBSTAR (warm boot start address) register to the location of the |
new configuration within the flash, and then writing a 15 (a.k.a. IPROG) |
to the FPGA command register (offset 4 from the beginning of the ICAPE2 |
addresses). Examples of doing this are found in the |
{\tt sw/host/zprog.sh} and {\tt sw/host/program.sh} scripts. The former |
programs the default configuration and then switches to it, |
|
This configuration capability makes it possible for a user to 1) reprogram |
the flash with an experimental configuration in the second configuration |
location, and 2) test the configuration without actually touching the board. |
If the configuration doesn't work well enough to be communicated with, the |
board may simply be powered down and it will come back up with the initial |
or golden configuration. If the golden configuration ever gets corrupted, |
or loaded with a configuration that will not work, then the user will need to |
reload the FPGA from the JTAG port. |
|
\subsection{OLED} |
\subsection{Real Time Clock} |
|
The Arty board contains a real time clock core together with a companion |
real time date/calendar core. The clock core itself contains not only current |
time, but also a stopwatch, seconds timer, and alarm. The real time date core |
can be used to maintain the current date. The real--time clock core uses the |
GPS PPS output, as schooled by the GPS tracking circuit, in order to synchronize |
their subsecond timing to the GPS itself. Further, the real--time clock core |
then creates a synchronization wire for the real--time date core. |
|
Neither of these cores exports its subsecond precision to the rest of the |
design. This must be done using either the internal GPS tracking wires, or |
by reading the time information from the tracking test bench. |
|
\subsection{LEDs} |
|
The Arty board contains two sets of LEDs: a plain set of LEDs, and a colored |
set of LEDs. |
|
The plain set of LEDs is controlled simply from the LED register. This register |
can be used to turn these LEDs on and off, either individually or as a whole. |
It has been designed for atomic access, so only one write to this register |
is necessary to set any particular LED. |
|
The color LEDs are slightly different. Each color LED is supported by its |
own register, which controls three pulse width modulation controllers. Three |
groups of eight bits within the color LED register control the PWM thresholds, |
first for red, then green, and then in the lowest bits for blue. These are |
used to turn on and off the various color components of the LEDs. Using this |
method, there are $2^{24}$ different colors each of these LEDs may be set |
to. |
|
\subsection{Buttons} |
\subsection{Switches} |
\subsection{Startup counter} |
|
A startup counter has been placed into the basic peripheral I/O area. This |
counter simply counts the clocks since startup. Upon rollover, the high |
order bit remains set. This can be used to sequence the start up of components |
within the design if so desired. |
|
\subsection{GPS UART} |
The GPS UART, debug control UART, as well as the auxilliary UART, are all |
based upon the same underlying UART IP core, sometimes known as the WBUART32 |
core. The setup register is defined within the documentation for that core, |
and provides for a large baud rate selection, 5-8 data bits, 1-2 stop bits, |
and several parity choices. Within OpenArty, the GPS core is initialized |
to 9.6~kBaud, 8 data bits, no parity, and one stop bit. |
|
When a value is ready to be read from the GPS uart, the GPS interrupt line |
will go high. Once read, and only when read, will this interrupt line reset. |
If the read is successful, only bits within the bottom eight will be set. |
If a read is attempted when there is no data, when the UART is in a reset |
condition, or when there has been a framing or parity error (were parity |
to be turned on), the upper bits of the UART port will be set. |
|
In a like manner, the GPS device can be written to. Certain strings, if sent |
to the UART, can be used to change the UARTs baud rate, its serial port |
settings, or even its reporting interval. As with the read port, the transmit |
port will interrupt the CPU when it is idle. Writing a character to this |
port will reset the interrupt. Setting bits other than the bottom eight may |
result in a break condition being set on this port as well. |
|
Interacting with a controller can therefore be somewhat tricky. The |
interrupt controller will trigger whenever the port is ready to be read from, |
and will re--trigger every clock until the port has been read from. At this |
point, the interrupt controller may be reset. If this is an auxilliary |
interrupt controller, such as the bus interrupt controller or the ZipSystem's |
auxiliary controller, the auxiliary controller will then need to be reset, |
and the bit in the primary controller associated with the auxiliary controller |
as well. It is for this reason that the UARTs have been placed on the |
primary controller only. |
|
It should also be possible to use the DMA to read from (or write to) either |
UART port. |
|
\subsection{Auxilliary UART} |
|
The Auxilliary UART has roughly the same structure as the GPS UART, save that |
it's default configuration is for a 115,200~Baud configuration with 8~data bits, |
no stop bits, and no parity. Reads, writes, and interrupts are treated in |
the same fashion. |
|
\subsection{GPIO} |
|
A General Purpose I/O controller has been placed within the design as well. |
This controller can handle 16--generic input wires, and set 16--generic output |
wires. A single register is used to read both input and output wire values, |
as well as to set output values when written to. |
|
However, to use this controller, you will need to manually configure it |
(i.e.~change the Verilog source) within the core, in order to wire the various |
GPIO values up to a device of interest. This was done for the simple reason |
that wiring anything new up to the controller will require Verilog changes |
anyway. For this reason, the controller has no way of setting wires to high |
impedence, or pulling them up or down. Such control may be done within the |
top level design if necessary. |
|
This controller will set an interrupt if ever any of the input wires within |
it are changed. The interrupt may be cleared in the interrupt controller. |
|
\subsection{Linker Script} |
|
A linker script has been created to capture the memory structure needed by |
a program. This script may be found in {\tt sw/board/arty.ld}. It is a |
sample script, using it is not required. |
|
The script defines three types of memory to the linker: flash, block RAM, and |
SDRAM. Programs using this script will naturally start in flash (acting as |
a ROM memory). A bootloader must then be used to copy, from flash, those |
sections of the program that are to be placed in block RAM or SDRAM into |
their particular memory locations. |
|
The block RAM locations are reserved for the user kernel, and specifically for |
any part of the code in the {\tt .kernel} section. C attributes, or assembly |
{\tt .section} commands, must be used to place items within this section. |
A final symbol within this section, {\_top\_of\_stack}, is used so that the |
initial boot loader knows what to set the initial kernel stack to. |
|
The rest of the initial program's memory is placed into |
SDRAM.\footnote{Hopefully, |
I'll get a data cache running on the ZipCPU to speed this up.} At the end, |
a {\tt \_top\_of\_heap} symbol is set to reference the final location in the |
setup. This symbol can then be used as a starting point for a memory allocator. |
|
An example bootloader is provided in {\tt sw/board} that can be linked with |
any (bare metal, supervisor) program in order to properly load it into memory. |
|
\chapter{Software} |
\section{Directory Structure} |
\section{Zip CPU Tool Chain} |
179,9 → 501,9
\end{itemize} |
\subsection{Scheduler} |
|
\chapter{Operation} |
\chapter{Operation}\label{ch:operation} |
|
\chapter{Registers} |
\chapter{Registers}\label{ch:registers} |
There are several address regions on the S6~SoC, as shown in |
Tbl.~\ref{tbl:memregions}. |
\begin{table}[htbp] |
258,11 → 580,14
GPSSETUP &\scalebox{0.8}{\tt 0x0107} & 29 & R/W & GPS UART config\\\hline |
CLR-LEDx &\scalebox{0.8}{\tt 0x0108-b} & 32 & R/W & Color LED controller\\\hline |
RTCDATE &\scalebox{0.8}{\tt 0x010c} & 32 & R/W & BCD Calendar Date\\\hline |
GPIO &\scalebox{0.8}{\tt 0x010d} & 32 & R/W & GPIO controller\\\hline |
GPIO &\scalebox{0.8}{\tt 0x010d} & 32 & R/W & {\em Reserved for} GPIO controller\\\hline |
UARTRX &\scalebox{0.8}{\tt 0x010e} & 32 & R/W & Aux UART receive byte\\\hline |
UARTTX &\scalebox{0.8}{\tt 0x010f} & 32 & R/W & Aux UART transmit byte\\\hline |
GPSRX &\scalebox{0.8}{\tt 0x0110} & 32 & R/W & GPS UART receive byte\\\hline |
GPSTX &\scalebox{0.8}{\tt 0x0111} & 32 & R/W & GPS UART transmit byte\\\hline |
GPSSECS &\scalebox{0.8}{\tt 0x0110} & 32 & R/W & {\em Reserved for a one-up seconds counter}\\\hline |
GPSSUB &\scalebox{0.8}{\tt 0x0110} & 32 & R/W & GPS PPS tracking subsecond info\\\hline |
GPSSTEP &\scalebox{0.8}{\tt 0x0111} & 32 & R/W & Current GPS step size, units TBD\\\hline |
% 0x010c-0x010f |
\end{reglist} |
\caption{I/O Peripheral Registers}\label{tbl:ioregs} |
290,23 → 615,23
\begin{table}[htbp] |
\begin{center}\begin{tabular}{|p{0.9in}|p{0.75in}|p{0.75in}|p{3.00in}|}\hline |
\rowcolor[gray]{0.85} Name & Bit Mask & DMAC ID &Description \\\hline\hline |
SYS\_DMAC & 0x0001 && The DMA controller is idle.\\\hline |
SYS\_JIF & 0x0002 & 1 & A Jiffies timer has expired.\\\hline |
SYS\_TMC & 0x0004 & 2 & Timer C has timed out.\\\hline |
SYS\_TMB & 0x0008 & 3 & Timer C has timed out.\\\hline |
SYS\_TMA & 0x0010 & 4 & Timer C has timed out.\\\hline |
SYS\_AUX & 0x0020 & 5 & The auxilliary interrupt controller sends an interrupt\\\hline |
SYS\_EXT & 0x0040 & 6 & A Bus interrupt has tripped. \\\hline |
SYS\_PPS & 0x0080 & 7 & An interrupt marking the top of the second\\\hline |
SYS\_GPSRX & 0x0100 & 8& A character has been received via GPS\\\hline |
SYS\_NETRX & 0x0200 & 9 & A packet has been received via the network\\\hline |
SYS\_NETTX & 0x0400 & 10 & The network controller is idle, having sent its |
SYS\_DMAC & 0x0001 && The DMA controller is idle.\\\hline |
SYS\_JIF & 0x0002 & 1 & A Jiffies timer has expired.\\\hline |
SYS\_TMC & 0x0004 & 2 & Timer C has timed out.\\\hline |
SYS\_TMB & 0x0008 & 3 & Timer C has timed out.\\\hline |
SYS\_TMA & 0x0010 & 4 & Timer C has timed out.\\\hline |
SYS\_AUX & 0x0020 & 5 & The auxilliary interrupt controller sends an interrupt\\\hline |
SYS\_PPS & 0x0040 & 6 & An interrupt marking the top of the second\\\hline |
SYS\_NETRX & 0x0080 & 7 & A packet has been received via the network\\\hline |
SYS\_NETTX & 0x0100 & 8 & The network controller is idle, having sent its |
last packet\\\hline |
SYS\_UARTRX & 0x0800 & 11 & A character has been received via the UART\\\hline |
SYS\_UARTTX & 0x1000 & 12 & The transmit UART is idle, and ready for its next |
SYS\_UARTRX & 0x200 & 9 & A character has been received via the UART\\\hline |
SYS\_UARTTX & 0x400 & 10 & The transmit UART is idle, and ready for its next |
character.\\\hline |
SYS\_GPSRX & 0x0800 & 11 & A character has been received via GPS\\\hline |
SYS\_GPSTX & 0x1000 & 12 & The GPS serial port transmit is idle\\\hline |
SYS\_SDCARD & 0x2000 & 13 & The SD-Card controller has become idle\\\hline |
SYS\_BUTTON & 0x4000 & 14 & A Button has been pressed. \\\hline |
SYS\_OLED & 0x4000 & 14 & The OLED port is idle\\\hline |
\end{tabular} |
\caption{Primary System Interrupts}\label{tbl:sys-ints} |
\end{center}\end{table} |
322,13 → 647,13
AUX\_MPC & 0x0020 & 21 & The supervisor prefetch stall counter has overflowed.\\\hline |
AUX\_MOC & 0x0040 & 22 & The supervisor ops stall counter has overflowed.\\\hline |
AUX\_MTC & 0x0080 & 23 & The supervisor clock tick counter has overflowed.\\\hline |
AUX\_SWITCH & 0x0100 & 24 & A switch has changed state\\\hline |
AUX\_FLASH & 0x0200 & 25 & The flash controller has completed a write/erase cycle\\\hline |
AUX\_SCOPE & 0x0400 & 26 & The Scope has completed its collection\\\hline |
AUX\_RTC & 0x0800 & 27& An alarm or timer has taken place (assuming the RTC |
AUX\_RTC & 0x0100 & 24& An alarm or timer has taken place (assuming the RTC |
is installed, and includes both alarm or timer)\\\hline |
AUX\_GPIO & 0x1000 & 28 & The GPIO input lines have changed values.\\\hline |
AUX\_OLED & 0x2000 & 29 & The OLED driver is idle\\\hline |
AUX\_BTN & 0x0200 & 25 & A button has been pressed\\\hline |
AUX\_SWITCH & 0x0400 & 26 & A switch has changed state\\\hline |
AUX\_FLASH & 0x0800 & 27 & The flash controller has completed a write/erase cycle\\\hline |
AUX\_SCOPE & 0x1000 & 28 & The Scope has completed its collection\\\hline |
AUX\_GPIO & 0x2000 & 29 & The GPIO input lines have changed values.\\\hline |
\end{tabular} |
\caption{Auxilliary System Interrupts}\label{tbl:aux-ints} |
\end{center}\end{table} |
/rtl/builddate.v
38,4 → 38,4
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`define DATESTAMP 32'h20161024 |
`define DATESTAMP 32'h20161027 |
/rtl/busmaster.v
141,7 → 141,7
// The GPS PMod |
i_gps_pps, i_gps_3df |
); |
parameter ZA=28, ZIPINTS=14, RESET_ADDRESS=28'h04e0000; |
parameter ZA=28, ZIPINTS=15, RESET_ADDRESS=28'h04e0000; |
input i_clk, i_rst; |
// The bus commander, via an external uart port |
input i_rx_stb; |
228,7 → 228,8
// Interrupts |
wire gpio_int, oled_int, flash_int, scop_int; |
wire enet_tx_int, enet_rx_int, sdcard_int, rtc_int, rtc_pps, |
auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int; |
auxrx_int, auxtx_int, gpsrx_int, gpstx_int, |
sw_int, btn_int; |
|
// |
// |
292,10 → 293,12
`ifdef ZIP_SYSTEM |
wire [(ZIPINTS-1):0] zip_interrupt_vec = { |
// Lazy(ier) interrupts |
oled_int, gpio_int, rtc_int, scop_int, flash_int, sw_int, btn_int, |
gpio_int, scop_int, flash_int, sw_int, btn_int, rtc_int, |
// Fast interrupts |
sdcard_int, auxtx_int, auxrx_int, enet_tx_int, enet_rx_int, |
gpsrx_int, rtc_pps |
oled_int, sdcard_int, |
gpstx_int, gpsrx_int, |
auxtx_int, auxrx_int, |
enet_tx_int, enet_rx_int, rtc_pps |
}; |
|
zipsystem #( .RESET_ADDRESS(RESET_ADDRESS), |
655,7 → 658,7
assign master_ints = { zip_cpu_int, oled_int, rtc_int, sdcard_int, |
enet_tx_int, enet_rx_int, |
scop_int, flash_int, rtc_pps }; |
wire [5:0] board_ints; |
wire [6:0] board_ints; |
wire [3:0] w_led; |
wire rtc_ppd; |
fastio #( |
670,7 → 673,7
rtc_ppd, |
bus_err_addr, gps_now[63:32], gps_step[47:16], master_ints, w_interrupt, |
board_ints); |
assign { gpio_int, auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int } = board_ints; |
assign { gpio_int, auxrx_int, auxtx_int, gpsrx_int, gpstx_int, sw_int, btn_int } = board_ints; |
|
/* |
reg [25:0] dbg_counter_err, dbg_counter_cyc, dbg_counter_sel, |
/rtl/cpu/wbdmac.v
332,9 → 332,10
|
initial o_interrupt = 1'b0; |
always @(posedge i_clk) |
o_interrupt <= (dma_state == `DMA_WRITE_ACK)&&(i_mwb_ack) |
&&(last_write_ack) |
&&(cfg_len == {{(AW-1){1'b0}},1'b1}); |
o_interrupt <= ((dma_state == `DMA_WRITE_ACK)&&(i_mwb_ack) |
&&(last_write_ack) |
&&(cfg_len == {{(AW-1){1'b0}},1'b1})) |
||((dma_state != `DMA_IDLE)&&(i_mwb_err)); |
|
initial cfg_err = 1'b0; |
always @(posedge i_clk) |
/rtl/fastio.v
50,7 → 50,7
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, |
i_wb_data, o_wb_ack, o_wb_stall, o_wb_data, |
// Cross-board I/O |
i_rtc_ppd, i_buserr, i_gps_now, i_gps_step, i_other_ints, o_bus_int, o_board_ints); |
i_rtc_ppd, i_buserr, i_gps_sub, i_gps_step, i_other_ints, o_bus_int, o_board_ints); |
parameter AUXUART_SETUP = 30'd1736, // 115200 baud from 200MHz clk |
GPSUART_SETUP = 30'd20833, // 9600 baud from 200MHz clk |
EXTRACLOCK = 1, // Do we need an extra clock to process? |
93,7 → 93,7
// Address of the last bus error |
input [31:0] i_buserr; |
// The current time, as produced by the GPS tracking processor |
input [31:0] i_gps_now, i_gps_step; |
input [31:0] i_gps_sub, i_gps_step; |
// |
// Interrupts -- both the output bus interrupt, as well as those |
// internally generated interrupts which may be used elsewhere |
100,7 → 100,7
// in the design |
input wire [8:0] i_other_ints; |
output wire o_bus_int; |
output wire [5:0] o_board_ints; // Button and switch interrupts |
output wire [6:0] o_board_ints; // Button and switch interrupts |
|
wire [31:0] w_wb_data; |
wire [4:0] w_wb_addr; |
133,7 → 133,7
reg sw_int, btn_int; |
wire pps_int, rtc_int, netrx_int, nettx_int, |
auxrx_int, auxtx_int, gpio_int, flash_int, scop_int, |
gpsrx_int, sd_int, oled_int, zip_int; |
gpsrx_int, gpstx_int, sd_int, oled_int, zip_int; |
assign { zip_int, oled_int, rtc_int, sd_int, |
nettx_int, netrx_int, scop_int, flash_int, |
pps_int } = i_other_ints; |
381,7 → 381,7
r_auxrx_data[8] <= !auxrx_stb; |
assign o_aux_cts = auxrx_stb; |
assign auxrx_data = { 20'h00, r_auxrx_data }; |
assign auxrx_int = r_auxrx_data[8]; |
assign auxrx_int = !r_auxrx_data[8]; |
|
// |
// Then the auxilliary UART transmitter |
405,7 → 405,7
r_auxtx_data <= 8'h0; |
end |
assign auxtx_data = { 20'h00, |
auxck_uart, o_aux_tx, r_auxtx_break, auxtx_busy, |
1'b0, o_aux_tx, r_auxtx_break, auxtx_busy, |
r_auxtx_data }; |
assign auxtx_int = ~auxtx_busy; |
|
436,7 → 436,7
if(((i_wb_stb)&&(~i_wb_we)&&(i_wb_addr == 5'h10))||(gpsrx_stb)) |
r_gpsrx_data[8] <= !gpsrx_stb; |
assign gpsrx_data = { 20'h00, r_gpsrx_data }; |
assign gpsrx_int = r_gpsrx_data[8]; |
assign gpsrx_int = !r_gpsrx_data[8]; |
|
|
// Then the transmitter |
461,6 → 461,7
assign gpstx_data = { 20'h00, |
gpsck_uart, o_gps_tx, r_gpstx_break, gpstx_busy, |
r_gpstx_data }; |
assign gpstx_int = !gpstx_busy; |
|
always @(posedge i_clk) |
case(i_wb_addr) |
482,8 → 483,9
5'h0f: o_wb_data <= auxtx_data; |
5'h10: o_wb_data <= gpsrx_data; |
5'h11: o_wb_data <= gpstx_data; |
5'h12: o_wb_data <= i_gps_now; |
5'h13: o_wb_data <= i_gps_step; |
// 5'h12: o_wb_data <= i_gps_secs; |
5'h13: o_wb_data <= i_gps_sub; |
5'h14: o_wb_data <= i_gps_step; |
// 5'hf: UART_SETUP |
// 4'h6: GPIO |
// ?? : GPS-UARTRX |
494,7 → 496,8
assign o_wb_stall = 1'b0; |
always @(posedge i_clk) |
o_wb_ack <= (i_wb_stb); |
assign o_board_ints = { gpio_int, auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int }; |
assign o_board_ints = { gpio_int, auxrx_int, auxtx_int, |
gpsrx_int, gpstx_int, sw_int, btn_int }; |
|
|
endmodule |
/rtl/wbgpio.v
0,0 → 1,81
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbgpio.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: A General Purpose Input/Output controller. This controller |
// allows a user to read the current state of the 16-GPIO input |
// pins, or to set the state of the 16-GPIO output pins. Specific numbers |
// of pins are configurable from 1-16. |
// |
// Unlike other controllers, this controller offers no capability to |
// change input/output direction, or to implement pull-up or pull-down |
// resistors. It simply changes and adjusts the values going out the |
// output pins, while allowing a user to read the values on the input |
// pins. |
// |
// Any change of an input pin value will result in the generation of an |
// interrupt signal. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
module wbgpio(i_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data, o_wb_data, |
i_gpio, o_gpio, o_int); |
parameter NIN=16, NOUT=16, DEFAULT=16'h00; |
input i_clk; |
// |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input [31:0] i_wb_data; |
output wire [31:0] o_wb_data; |
// |
input [(NIN-1):0] i_gpio; |
output reg [(NOUT-1):0] o_gpio; |
// |
output reg o_int; |
|
// 9LUT's, 16 FF's |
always @(posedge i_clk) |
if ((i_wb_stb)&&(i_wb_we)) |
o_gpio <= ((o_gpio)&(~i_wb_data[(NOUT+16-1):16])) |
|((i_wb_data[(NOUT-1):0])&(i_wb_data[(NOUT+16-1):16])); |
|
reg [(NIN-1):0] x_gpio, r_gpio; |
// 3 LUTs, 33 FF's |
always @(posedge i_clk) |
begin |
x_gpio <= i_gpio; |
r_gpio <= x_gpio; |
o_int <= (x_gpio != r_gpio); |
end |
|
assign o_wb_data = { {(16-NIN){1'b0}}, r_gpio, |
{(16-NOUT){1'b0}}, o_gpio }; |
endmodule |
/rtl/wboled.v
144,7 → 144,7
o_ack, o_stall, o_data, |
o_sck, o_cs_n, o_mosi, o_dbit, |
o_pwr, o_int); |
parameter CBITS=8, // 2^4*2@6.25ns -> 200ns/clock > 150ns min |
parameter CBITS=4, // 2^4*13ns -> 208ns/clock > 150ns min |
EXTRA_BUS_CLOCK = 0; |
input i_clk, i_cyc, i_stb, i_we; |
input [1:0] i_addr; |
/sw/board/Makefile
31,11 → 31,12
## |
## |
.PHONY: all |
all: exstartup oledtest gpsdump |
PROGRAMS := exstartup oledtest gpsdump exmulti |
all: $(PROGRAMS) |
OBJDIR := obj-zip |
CC := zip-gcc |
OBJDUMP := zip-objdump |
SOURCES := exstartup.c bootloader.c gpsdump.c oledtest.c |
SOURCES := exstartup.c bootloader.c gpsdump.c oledtest.c exmulti.c |
HEADERS := artyboard.h zipsys.h |
# |
# For source analysis, the following macros are defined: |
44,7 → 45,7
|
%.o: $(OBJDIR)/%.o |
$(OBJDIR)/%.o: %.c |
$(CC) -c -fno-builtin $< -o $@ |
$(CC) -O3 -c -fno-builtin $< -o $@ |
%.txt: % |
$(OBJDUMP) -S -D $^ > $@ |
|
53,13 → 54,16
gpsdump: $(OBJDIR)/gpsdump.o $(OBJDIR)/bootloader.o arty.ld |
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=gpsdump.map $(OBJDIR)/gpsdump.o $(OBJDIR)/bootloader.o -o $@ |
oledtest: $(OBJDIR)/oledtest.o $(OBJDIR)/bootloader.o $(OBJDIR)/splash.o $(OBJDIR)/mug.o arty.ld |
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=gpsdump.map $(OBJDIR)/oledtest.o $(OBJDIR)/bootloader.o $(OBJDIR)/splash.o $(OBJDIR)/mug.o -o $@ |
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=oledtest.map $(OBJDIR)/oledtest.o $(OBJDIR)/bootloader.o $(OBJDIR)/splash.o $(OBJDIR)/mug.o -o $@ |
|
exmulti: $(OBJDIR)/exmulti.o $(OBJDIR)/bootloader.o arty.ld |
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=exmulti.map $(OBJDIR)/exmulti.o $(OBJDIR)/bootloader.o -o $@ |
|
exstartup.txt: exstartup |
$(OBJDUMP) -S -D $^ > $@ |
|
clean: |
rm -f exstartup exstartup.map exstartup.txt |
rm -rf $(PROGRAMS) $(addsuffix .map,$(PROGRAMS)) $(addsuffix .txt,$(PROGRAMS)) |
rm -rf $(OBJDIR)/ |
|
define build-depends |
/sw/board/artyboard.h
57,6 → 57,23
#define BUS_SDCARD 0x1000 |
#define BUS_OLED 0x2000 |
#define BUS_ZIP 0x4000 |
|
// DMA Interrupt parameters |
#define DMA_JIFFIES (DMA_TRIGGER|0x0400) |
#define DMA_TMC (DMA_TRIGGER|0x0800) |
#define DMA_TMB (DMA_TRIGGER|0x0c00) |
#define DMA_TMA (DMA_TRIGGER|0x1000) |
#define DMA_AUX (DMA_TRIGGER|0x1400) |
#define DMA_PPS (DMA_TRIGGER|0x1800) |
#define DMA_NETRX (DMA_TRIGGER|0x1c00) |
#define DMA_NETTX (DMA_TRIGGER|0x2000) |
#define DMA_UARTRX (DMA_TRIGGER|0x2400) |
#define DMA_UARTTX (DMA_TRIGGER|0x2800) |
#define DMA_GPSRX (DMA_TRIGGER|0x2c00) |
#define DMA_GPSTX (DMA_TRIGGER|0x3000) |
#define DMA_SDCARD (DMA_TRIGGER|0x3400) |
#define DMA_OLED (DMA_TRIGGER|0x3800) |
|
// That's our maximum number of interrupts. Any more, and we'll need to |
// remove one. Don't forget, the primary interrupt source will be the SYS_ |
// interrupts, and there's another set of AUX_ interrupts--both available if |
84,7 → 101,7
|
typedef struct { |
volatile unsigned rxcmd, txcmd; |
volatile long mac; |
volatile unsigned mac[2]; |
volatile unsigned rxmiss, rxerr, rxcrc, txcol; |
#define ENET_TXGO 0x004000 |
#define ENET_TXBUSY 0x004000 |
139,7 → 156,8
volatile unsigned io_gpio; |
volatile unsigned io_uart_rx, io_uart_tx; |
volatile unsigned io_gps_rx, io_gps_tx; |
unsigned io_reserved[32-18]; |
volatile unsigned io_gps_sec, io_gps_sub, io_gps_step; |
unsigned io_reserved[32-21]; |
SCOPE io_scope[4]; |
RTC io_rtc; |
SDCARD io_sd; |
/sw/board/bootloader.c
96,6 → 96,41
#include "artyboard.h" |
#include "zipsys.h" |
|
// A bootloader is about nothing more than copying memory from a couple |
// particular locations (Flash/ROM) to other locations in memory (BLKRAM |
// and SDRAM). Our DMA is a hardware accelerator that does nothing but |
// copy memory from one location to another. Why not use the DMA for this |
// purpose then? |
// |
// Here, we have a USE_DMA #define. When this is defined, the memory copy |
// will be done using the DMA hardware accelerator. This is a good thing, |
// and this should be defined. There are two problems with defining this |
// however: 1) It obscures for any readers of this code what is actually |
// happening, and 2) it makes the code dependent upon yet another piece of the |
// hardware design working. For these reasons, we allow you to turn it off. |
#define USE_DMA |
|
// |
// _start: |
// |
// Every computer needs to start processing from somewhere on reboot, and every |
// program needs some entry point. For the ZipCPU, that starting place is the |
// routine with the _start symbol. It is important that this start symbol be |
// placed at the boot address for the CPU. This is the very first address of |
// program memory, and (currently) on the Arty board it is placed in Flash at |
// _start = 0x4e0000. To make certain this routine goes into the very first |
// address in flash, we place it into it's own special section, the .start |
// section, and then tell the linker that the .start section is the first |
// section where it needs to start placing code. |
// |
// If you read through this short assembly routine below, you'll find that it |
// does only a small number of tasks. It sets the stack pointer to point to |
// the top of the stack (a symbol defined in the linker file), calls the |
// bootloader, resets the stack pointer, clears any data cache, and then calls |
// the kernel entry function. It also sets up a return address for the kernel |
// entry function so that, should the kernel ever exit, it wouldn't exit on |
// any error but rather it would exit by halting the CPU. |
// |
asm("\t.section\t.start\n" |
"\t.global\t_start\n" |
"_start:\n" |
116,18 → 151,33
_blkram, _flash, _bss_image_end, |
_kernel_image_start, _kernel_image_end; |
|
// |
// We need to insist that the bootloader be kept in Flash, else it would depend |
// upon running a routine from memory that ... wasn't in memory yet. For this |
// purpose, we place the bootloader in a special .boot section. We'll also tell |
// the linker, via the arty.ld file, that thsi .boot section needs to be placed |
// into flash. |
// |
extern void bootloader(void) __attribute__ ((section (".boot"))); |
|
// #define USE_DMA |
// |
// bootloader() |
// |
// Here's the actual boot loader itself. It copies three areas from flash: |
// 1. An area from flash to block RAM |
// 2. A second area from flash to SDRAM |
// 3. The third area isn't copied from flash, but rather it is just set to |
// zero. This is sometimes called the BSS segment. |
// |
void bootloader(void) { |
int zero = 0; |
|
#ifdef USE_DMA |
zip->dma.ctrl= DMACLEAR; |
zip->dma.rd = _kernel_image_start; |
if (_kernel_image_end != _sdram_image_start) { |
zip->dma.len = _kernel_image_end - _blkram; |
zip->dma.wr = _blkram; |
zip->dma.rd = &_kernel_image_start; |
if (&_kernel_image_end != &_sdram_image_start) { |
zip->dma.len = &_kernel_image_end - &_blkram; |
zip->dma.wr = &_blkram; |
zip->dma.ctrl= DMACCOPY; |
|
zip->pic = SYSINT_DMAC; |
135,16 → 185,19
; |
} |
|
zip->dma.len = &_sdram_image_end - _sdram; |
zip->dma.wr = _sdram; |
zip->dma.ctrl= DMACCOPY; |
// zip->dma.rd // Keeps the same value |
zip->dma.wr = &_sdram; |
if (&_sdram_image_end != &_sdram) { |
zip->dma.len = &_sdram_image_end - &_sdram; |
zip->dma.ctrl= DMACCOPY; |
} |
|
zip->pic = SYSINT_DMAC; |
while((zip->pic & SYSINT_DMAC)==0) |
; |
|
if (_bss_image_end != _sdram_image_end) { |
zip->dma.len = _bss_image_end - _sdram_image_end; |
if (&_bss_image_end != &_sdram_image_end) { |
zip->dma.len = &_bss_image_end - &_sdram_image_end; |
zip->dma.rd = &zero; |
// zip->dma.wr // Keeps the same value |
zip->dma.ctrl = DMACCOPY; |
/sw/board/exmulti.c
0,0 → 1,372
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: exmulti.c |
// |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: Very similar to exstartup.c, the purpose of this program is to |
// demonstrate several working peripherals. To the exstartup |
// peripherals, we'll add the GPS and the GPS PPS tracking. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include "artyboard.h" |
#include "zipsys.h" |
|
void idle_task(void) { |
while(1) |
zip_idle(); |
} |
|
void wait_on_interrupt(int mask) { |
zip->pic = DALLPIC|mask; |
zip->pic = EINT(mask); |
zip_rtu(); |
} |
|
int user_stack[256]; |
void user_task(void) { |
const unsigned white = 0x070707, black = 0; |
while(1) { |
unsigned btn, subnow, sw; |
|
subnow = (sys->io_gps_sub >> 28)&0x0f; |
|
// If the button is pressed, toggle the LED |
// Otherwise, turn the LED off. |
// |
|
// First, get all the pressed buttons |
btn = (sys->io_btnsw) & 0x0f0; |
// Now, acknowledge the button presses that we just read |
sys->io_btnsw = btn; |
btn >>= 4; |
|
// Now, use the time as the toggle function. |
btn = (subnow ^ btn)&btn & 0x07; |
|
sys->io_ledctrl = btn | 0x070; |
|
sw = sys->io_btnsw & 0x0f; |
for(int i=0; i<4; i++) |
sys->io_clrled[i] = (sw & (1<<i)) ? white : black; |
|
} |
} |
|
int mpyuhi(int a, int b) { |
// err_in_ns = mpyuhi(err_in_ns, err); |
// __asm__("MPYUHI %1,%0" :"+r"(a):"r"(b)); |
unsigned alo, blo, ahi, bhi, f, o, i, l, rhi; |
|
alo = (a & 0x0ffff); |
ahi = (a >> 16)&0x0ffff; |
blo = (b & 0x0ffff); |
bhi = (b >> 16)&0x0ffff; |
|
l = alo * blo; |
o = ahi * blo; |
i = alo * bhi; |
f = ahi * bhi; |
|
rhi = o + i + (l >> 16); |
return (rhi >> 16) + f; |
// return f; |
// return ahi; |
} |
|
int hexdigit(int v) { |
if (v < 10) |
return v + '0'; |
else |
return v + 'A' - 10; |
} |
|
int errstring[128]; |
|
void entry(void) { |
const unsigned red = 0x0ff0000, green = 0x0ff00, blue = 0x0ff, |
white = 0x070707, black = 0, dimgreen = 0x1f00, |
second = 81250000; |
int i, sw; |
|
// Start the GPS converging ... |
sys->io_gps.g_alpha = 2; |
sys->io_gps.g_beta = 0x14bda12f; |
sys->io_gps.g_gamma = 0x1f533ae8; |
|
int user_context[16]; |
for(i=0; i<15; i++) |
user_context[i] = 0; |
user_context[15] = (unsigned)idle_task; |
zip_restore_context(user_context); |
|
for(i=0; i<4; i++) |
sys->io_clrled[i] = red; |
sys->io_ledctrl = 0x0ff; |
|
// Clear the PIC |
// |
// Acknowledge all interrupts, turn off all interrupts |
// |
zip->pic = 0x7fff7fff; |
while(sys->io_pwrcount < (second >> 4)) |
; |
|
// Repeating timer, every 250ms |
zip->tma = (second/4) | 0x80000000; |
wait_on_interrupt(SYSINT_TMA); |
|
sys->io_clrled[0] = green; |
sys->io_ledctrl = 0x010; |
|
wait_on_interrupt(SYSINT_TMA); |
|
sys->io_clrled[0] = dimgreen; |
sys->io_clrled[1] = green; |
sys->io_scope[0].s_ctrl = 32 | 0x80000000; // SCOPE_TRIGGER; |
sys->io_ledctrl = 0x020; |
|
wait_on_interrupt(SYSINT_TMA); |
|
sys->io_clrled[1] = dimgreen; |
sys->io_clrled[2] = green; |
sys->io_ledctrl = 0x040; |
|
wait_on_interrupt(SYSINT_TMA); |
|
sys->io_clrled[2] = dimgreen; |
sys->io_clrled[3] = green; |
sys->io_ledctrl = 0x080; |
|
wait_on_interrupt(SYSINT_TMA); |
|
sys->io_clrled[3] = dimgreen; |
|
wait_on_interrupt(SYSINT_TMA); |
|
for(i=0; i<4; i++) |
sys->io_clrled[i] = black; |
|
// Wait one second ... |
for(i=0; i<4; i++) |
wait_on_interrupt(SYSINT_TMA); |
|
// Blink all the LEDs |
// First turn them on |
sys->io_ledctrl = 0x0ff; |
// Then wait a quarter second |
wait_on_interrupt(SYSINT_TMA); |
// Then turn the back off |
sys->io_ledctrl = 0x0f0; |
// and wait another quarter second |
wait_on_interrupt(SYSINT_TMA); |
|
// Now, read buttons, and flash an LED on any button being held |
// down ... ? neat? |
|
// Now, let's synchronize ourselves to the PPS |
user_context[13] = (int)&user_stack[256]; |
user_context[15] = (int)&user_task; |
zip_restore_context(user_context); |
|
do { |
wait_on_interrupt(SYSINT_PPS|SYSINT_TMA); |
} while((zip->pic & SYSINT_PPS)==0); |
|
while(1) { |
int *s = errstring; |
|
zip->wdt = CLOCKFREQ_HZ*4; |
sys->io_ledctrl = 0x088; |
|
// 1. Read and report the GPS tracking err |
|
// Get the upper 32-bits of the error; |
int err = *(int *)(&sys->io_gpstb.tb_err); |
int err_in_ns; |
/* |
long err_in_ns_long = err; |
err_in_ns_long *= 1000000000l; |
err_in_ns_long >>= 32; |
int err_in_ns = (int)(err_in_ns_long); |
*/ |
int err_sgn = (err < 0)?1:0; |
err_in_ns = (err<0)?-err:err; |
err_in_ns = mpyuhi(err_in_ns, 1000000000); |
int digit; |
|
|
*s++ = '\r'; |
*s++ = '\n'; |
*s++ = 'G'; |
*s++ = 'P'; |
*s++ = 'S'; |
*s++ = ' '; |
*s++ = 'P'; |
*s++ = 'P'; |
*s++ = 'S'; |
*s++ = ' '; |
*s++ = 'E'; |
*s++ = 'r'; |
*s++ = 'r'; |
*s++ = ':'; |
*s++ = ' '; |
|
|
*s++ = '0'; |
*s++ = 'x'; |
*s++ = hexdigit((err>>28)&0x0f); |
*s++ = hexdigit((err>>24)&0x0f); |
*s++ = hexdigit((err>>20)&0x0f); |
*s++ = hexdigit((err>>16)&0x0f); |
*s++ = hexdigit((err>>12)&0x0f); |
*s++ = hexdigit((err>> 8)&0x0f); |
*s++ = hexdigit((err>> 4)&0x0f); |
*s++ = hexdigit((err )&0x0f); |
|
*s++ = ' '; |
*s++ = '='; |
*s++ = '>'; |
*s++ = ' '; |
|
*s++ = '0'; |
*s++ = 'x'; |
*s++ = hexdigit((err_in_ns>>28)&0x0f); |
*s++ = hexdigit((err_in_ns>>24)&0x0f); |
*s++ = hexdigit((err_in_ns>>20)&0x0f); |
*s++ = hexdigit((err_in_ns>>16)&0x0f); |
*s++ = hexdigit((err_in_ns>>12)&0x0f); |
*s++ = hexdigit((err_in_ns>> 8)&0x0f); |
*s++ = hexdigit((err_in_ns>> 4)&0x0f); |
*s++ = hexdigit((err_in_ns )&0x0f); |
|
*s++ = ' '; |
*s++ = '='; |
*s++ = '>'; |
*s++ = ' '; |
|
*s++ = (err_sgn)?'-':' '; |
// Milliseconds |
digit = err_in_ns / 100000000; |
*s++ = digit+'0'; |
err_in_ns -= digit * 100000000; |
// |
digit = err_in_ns / 10000000; |
*s++ = digit+'0'; |
err_in_ns -= digit * 10000000; |
// |
digit = err_in_ns / 1000000; |
*s++ = digit+'0'; |
err_in_ns -= digit * 1000000; |
// Micro seconds |
digit = err_in_ns / 100000; |
*s++ = digit+'0'; |
err_in_ns -= digit * 100000; |
// |
digit = err_in_ns / 10000; |
*s++ = digit+'0'; |
err_in_ns -= digit * 10000; |
// |
digit = err_in_ns / 1000; |
*s++ = digit+'0'; |
err_in_ns -= digit * 1000; |
// Nano seconds |
*s++ = '.'; |
digit = err_in_ns / 100; |
*s++ = digit+'0'; |
err_in_ns -= digit * 100; |
// |
digit = err_in_ns / 10; |
*s++ = digit+'0'; |
err_in_ns -= digit * 10; |
// |
digit = err_in_ns; |
*s++ = digit+'0'; |
// |
*s++ = ' '; |
*s++ = 'u'; |
*s++ = 'S'; |
*s++ = '\r'; |
*s++ = '\n'; |
*s++ = '\r'; |
*s++ = '\n'; |
*s++ = '\0'; |
|
/* |
zip->dma.ctrl = DMACLEAR; |
zip->dma.rd = errstring; |
zip->dma.wr = &sys->io_uart_tx; |
zip->dma.len = s - errstring-1; |
zip->dma.ctrl = (DMAONEATATIME|DMA_CONSTDST|DMA_GPSRX); |
wait_on_interrupt(SYSINT_DMAC); |
*/ |
|
for(int i=0; errstring[i]; i++) { |
wait_on_interrupt(SYSINT_UARTTX); |
sys->io_uart_tx = errstring[i]; |
zip->pic = SYSINT_UARTTX; |
} |
|
sys->io_ledctrl = 0x080; |
|
/* |
zip->dma.rd = &sys->io_gps_rx; |
zip->dma.wr = &sys->io_uart_tx; |
zip->dma.len = 0x01000000; |
zip->dma.ctrl = (DMAONEATATIME|DMA_CONSTDST|DMA_CONSTSRC|DMA_GPSRX); |
wait_on_interrupt(SYSINT_PPS); |
*/ |
|
/* |
if (zip_ucc() & CC_FAULT) { |
zip_save_context(user_context); |
user_context[14] = CC_GIE; |
user_context[15] = (int)&idle_task; |
zip_restore_context(user_context); |
} |
*/ |
|
zip->pic = SYSINT_GPSRX | SYSINT_PPS; |
do { |
wait_on_interrupt(SYSINT_PPS|SYSINT_GPSRX); |
if (zip->pic & SYSINT_GPSRX) { |
sys->io_uart_tx = sys->io_gps_rx; |
zip->pic = SYSINT_GPSRX; |
} |
} while((zip->pic & SYSINT_PPS)==0); |
|
// wait_on_interrupt(SYSINT_PPS); |
// zip->dma.ctrl= DMACLEAR; |
} |
|
zip_halt(); |
} |
|
/sw/board/exstartup.c
1,3 → 1,42
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: exstartup.c |
// |
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: A fun example program that runs on the Arty, just to show |
// that the minimum set of peripherals (LEDs, color LEDs, buttons, |
// switches, etc.) work. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include "artyboard.h" |
#include "zipsys.h" |
|
/sw/board/gpsdump.c
35,9 → 35,12
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#include "zipsys.h" |
#include "artyboard.h" |
|
void entry(void) { |
/* |
// Method one: direct polling |
while(1) { |
int ch; |
ch = sys->io_gps_rx; |
44,4 → 47,29
if ((ch&-256)==0) |
sys->io_uart_tx = ch; |
} |
*/ |
// Method two: Waiting on interrupts |
zip->pic = SYSINT_GPSRX; |
while(1) { |
while((zip->pic & SYSINT_GPSRX)==0) |
; |
sys->io_uart_tx = sys->io_gps_rx; |
zip->pic = SYSINT_GPSRX; |
} |
|
/* |
// Method three: Use the DMA |
zip->dma.ctrl = DMACLEAR; |
while(1) { |
zip->dma.rd = &sys->io_gps_rx; |
zip->dma.wr = &sys->io_uart_tx; |
zip->dma.len = 0x01000000; // More than we'll ever do ... |
zip->dma.ctrl = (DMAONEATATIME|DMA_CONSTDST|DMA_CONSTSRC|DMA_GPSRX); |
// zip->dma.ctrl = (DMAONEATATIME|DMA_CONSTDST|DMA_CONSTSRC); |
|
while(zip->dma.ctrl & 0x80000000) |
if (zip->dma.ctrl & 0x40000000) |
zip_halt();; |
} |
*/ |
} |
/sw/board/oledtest.c
40,8 → 40,8
// |
// |
|
#include "zipsys.h" |
#include "artyboard.h" |
#include "zipsys.h" |
|
void idle_task(void) { |
while(1) |
89,6 → 89,13
} // else anything less has likely already passed |
} |
|
void wait_on_interrupt(int mask) { |
// Clear our interrupt only, but disable all others |
zip->pic = DALLPIC|mask; |
zip->pic = EINT(mask); |
zip_rtu(); |
zip->pic = DINT(mask)|mask; |
} |
|
void oled_clear(void); |
|
260,6 → 267,24
; |
} |
|
void oled_show_image(int *img) { |
#define USE_DMA |
#ifdef USE_DMA |
zip->dma.ctrl = DMACLEAR; |
zip->dma.rd = img; |
zip->dma.wr = &sys->io_oled.o_data; |
zip->dma.len= 6144; |
zip->dma.ctrl = DMAONEATATIME|DMA_CONSTDST|DMA_OLED; |
// timer_delay(256); |
// zip_halt(); |
#else |
for(int i=0; i<6144; i++) { |
while(sys->io_oled.o_ctrl & OLED_BUSY) |
; |
sys->io_oled.o_data = img[i]; |
} |
#endif |
} |
|
/* |
* entry() |
266,7 → 291,7
* |
* In all (current) ZipCPU programs, the programs start with an entry() |
* function that takes no arguments. The actual bootup entry can be found |
* in the bootstram directory, but that calls us here. |
* in the bootstrap.c file, but that calls us here. |
* |
*/ |
void entry(void) { |
375,11 → 400,8
sys->io_oled.o_ctrl = 0x2075003f; // Sets row min/max address |
|
// Now ... finally ... we can send our image. |
for(int i=0; i<6144; i++) { |
while(sys->io_oled.o_ctrl & OLED_BUSY) |
; |
sys->io_oled.o_data = splash[i]; |
} |
oled_show_image(splash); |
wait_on_interrupt(SYSINT_DMAC); |
|
// Wait 25 seconds. The LEDs are for a fun effect. |
sys->io_ledctrl = 0x0f1; |
396,11 → 418,8
|
// Display a second image. |
sys->io_ledctrl = 0x0fc; |
for(int i=0; i<6144; i++) { |
while(sys->io_oled.o_ctrl & OLED_BUSY) |
; |
sys->io_oled.o_data = mug[i]; |
} |
oled_show_image(mug); |
wait_on_interrupt(SYSINT_DMAC); |
|
// Leave this one in effect for 5 seconds only. |
sys->io_ledctrl = 0x0f8; |
/sw/board/zipsys.h
48,8 → 48,15
volatile int *rd, *wr; |
} ZIPDMA; |
|
#define DMA_TRIGGER 0x00008000 |
#define DMACLEAR 0xffed0000 |
#define DMACCOPY 0x0fed0000 |
#define DMACERR 0x40000000 |
#define DMA_CONSTSRC 0x20000000 |
#define DMA_CONSTDST 0x10000000 |
#define DMAONEATATIME 0x0fed0001 |
#define DMA_BUSY 0x80000000 |
#define DMA_ERR 0x40000000 |
|
typedef struct { |
volatile int pic, wdt, err, apic, tma, tmb, tmc, |
66,22 → 73,28
#define SYSINT_TMB 0x0008 |
#define SYSINT_TMA 0x0010 |
#define SYSINT_AUX 0x0020 |
#define SYSINT_BRD 0x0040 |
// |
#define SYSINT_CK 0x0080 |
#define SYSINT_FLASH 0x0100 |
#define SYSINT_SCOP 0x0200 |
#define SYSINT_GPIO 0x0400 |
#define SYSINT_PWM 0x0800 |
#define SYSINT_UARTRX 0x1000 |
#define SYSINT_UARTTX 0x2000 |
#define SYSINT_SDCARD 0x4000 |
#define SYSINT_PPS 0x0040 |
#define SYSINT_NETRX 0x0080 |
#define SYSINT_NETTX 0x0100 |
#define SYSINT_UARTRX 0x0200 |
#define SYSINT_UARTTX 0x0400 |
#define SYSINT_GPSRX 0x0800 |
#define SYSINT_GPSTX 0x1000 |
#define SYSINT_SDCARD 0x2000 |
#define SYSINT_OLED 0x4000 |
|
|
#define ALTINT_UIC 0x001 |
#define ALTINT_UTC 0x008 |
#define ALTINT_MIC 0x010 |
#define ALTINT_MTC 0x080 |
#define ALTINT_UIC 0x0001 |
#define ALTINT_UTC 0x0008 |
#define ALTINT_MIC 0x0010 |
#define ALTINT_MTC 0x0080 |
#define ALTINT_RTC 0x0100 |
#define ALTINT_BTN 0x0200 |
#define ALTINT_SWITCH 0x0400 |
#define ALTINT_FLASH 0x0800 |
#define ALTINT_SCOPE 0x1000 |
#define ALTINT_GPIO 0x2000 |
|
|
#define CC_Z 0x0001 |
98,6 → 111,9
#define CC_DIVERR 0x0800 |
#define CC_FPUERR 0x1000 |
#define CC_IPHASE 0x2000 |
#define CC_MMUERR 0x8000 |
#define CC_EXCEPTION (CC_ILL|CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_MMUERR) |
#define CC_FAULT (CC_ILL|CC_BUSERR|CC_DIVERR|CC_FPUERR) |
|
// extern void zip_break(void); |
extern void zip_rtu(void); |
121,8 → 137,9
#endif |
|
#define EINT(A) (0x80000000|(A<<16)) |
#define DINT(A) (0x80000000|(A<<16)) |
#define DINT(A) (0x00000000|(A<<16)) |
#define CLEARPIC 0x7fff7fff |
#define DALLPIC 0x7fff0000 // Disable all PIC interrupt sources |
|
static ZIPSYS *const zip = (ZIPSYS *)(ZIPSYS_ADDR); |
|
/sw/host/zipstate.cpp
70,7 → 70,7
printf("ERR: errcount(%d) >= MAXERR on cmd_read(a=%02x)\n", |
errcount, r); |
printf("ZIPCTRL = 0x%08x", s); |
if ((s & 0x0200)==0) printf(" STALL"); |
if ((s & 0x0200)==0) printf(" BUSY"); |
if (s & 0x0400) printf(" HALTED"); |
if ((s & 0x03000)==0x01000) |
printf(" SW-HALT"); |
109,7 → 109,7
printf("0x%08x: ", v); |
if (v & 0x0080) printf("PINT "); |
// if (v & 0x0100) printf("STEP "); // self resetting |
if((v & 0x00200)==0) printf("STALL "); |
if((v & 0x00200)==0) printf("BUSY "); |
if (v & 0x00400) printf("HALTED "); |
if((v & 0x03000)==0x01000) { |
printf("SW-HALT"); |