OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 35 to Rev 36
    Reverse comparison

Rev 35 → Rev 36

/openarty/trunk/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 :=
/openarty/trunk/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
/openarty/trunk/doc/spec.pdf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/openarty/trunk/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}
/openarty/trunk/rtl/builddate.v
38,4 → 38,4
////////////////////////////////////////////////////////////////////////////////
//
//
`define DATESTAMP 32'h20161024
`define DATESTAMP 32'h20161027
/openarty/trunk/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,
/openarty/trunk/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)
/openarty/trunk/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
/openarty/trunk/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
/openarty/trunk/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;
/openarty/trunk/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
/openarty/trunk/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;
/openarty/trunk/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;
/openarty/trunk/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();
}
 
/openarty/trunk/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"
 
/openarty/trunk/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();;
}
*/
}
/openarty/trunk/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;
/openarty/trunk/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);
 
/openarty/trunk/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");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.