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

Subversion Repositories ion

[/] [ion/] [trunk/] [doc/] [src/] [tex/] [soc.tex] - Rev 221

Compare with Previous | Blame | View Log

 
\chapter{SoC Module}
\label{soc_module}
 
The main purpose of the SoC module is to encapsulate the somewhat complex 
interconnection between the CPU and the Cache/Memory Controller module.
 
If some project demands that some piece of hardware be directly connected to the
CPU, bypassing the cache, this is where it should be -- an MMU comes to mind.
 
Any peripherals deemed common enough that they will be present in all projects
might be placed in the SoC module too.
 
In the current version of the SoC module, there is only one peripheral included 
in it -- a hardwired UART module. There is no penalty for placing peripherals 
ouside the SoC module, so there is no incentive to place them inside. This is 
an implementation option of yours.\\
 
Bear in mind that, in its current state, the SoC module is little more than a 
vehicle for building demos around the ION CPU. It is not meant as a real-world
SoC, though it might be deloped into one eventually.
 
\section{SoC Generics}
\label{soc_generics}
 
    The SoC needs to be configured upon instantiation by setting the following
    generics:
 
\begin{table}[h]
\caption{SoC module generics\label{tab_soc_generics}}
\begin{tabularx}{\textwidth}{ lll|X }
\toprule
Name & Type & Default value & Description \\
\midrule
\texttt{BOOT\_BRAM\_SIZE}      & integer    & 1024  & Bootstrap BRAM size in 32-bit words. \\
\texttt{OBJ\_CODE}     & t\_obj\_code & (void code) & Bootstrap BRAM contents. \\
\midrule
\texttt{CLOCK\_FREQ}   & integer    & 50e6  & Main clock rate. \\
\texttt{BAUD\_RATE}    & integer    & 19200  & UART baud rate. \\
\midrule
\texttt{SRAM\_ADDR\_SIZE} & integer & 17 & Size of SRAM address bus. \\
\bottomrule
\end{tabularx}
\end{table}   
 
The current version of the SoC is not very strict in the enforcement of limits 
for the generics. You are advised to use only 'reasonable' values. This will 
be fixed, eventually.
 
Generic \texttt{CLOCK\_FREQ} is only needed in order to compute the default 
baud period for the internal UART (from the value of generic \texttt{BAUD\_RATE}).
 
 
Generic \texttt{BOOT\_BRAM\_SIZE} will determine the size of the internal 
bootstrap BRAM. This generic \emph{can't be zero}; in the current version of
the SoC, the BRAM can't be disabled or omitted.
 
Note that if the size of the bootstrap BRAM is not enough to hold the whole 
bootstrap code provided in generic \texttt{OBJ\_CODE}, the code \emph{will 
be sineltly truncated!}. Usually this will result in an early crash.
 
Generic \texttt{OBJ\_CODE} is used at synthesis time to initialize the bootstrap
BRAM. This generic is meant to contain boostrap code, as seen in section 
~\ref{bootstrap_code}). It can be omitted, in which case the bootstrap BRAM
will be initialized to all zeros.
 
 
\section{SoC Ports}
\label{soc_ports}
 
\begin{figure}[h]
\makebox[\textwidth]{\framebox[9cm]{\rule{0pt}{9cm}
\includegraphics[width=8cm]{img/soc_symbol.png}}}
\caption{SoC module interface\label{soc_symbol}}
\end{figure}
 
\begin{table}[h]
\caption{SoC module interface ports}
\begin{tabularx}{\textwidth}{ lll|X }
\toprule
Name & Type & Width & Description \\
\midrule
clk                 & in    & 1  & Clock input, active rising edge. \\
reset               & in    & 1  & Synchronous global reset. \\
\midrule
sram\_address       & out   & 16 & Memory word address (bit 0 absent). \\
sram\_data\_wr      & out   & 16 & Memory write data. Only valid when one of the \\
                    &       &    & memory byte write enable outputs is active.\\
sram\_data\_rd      & in    & 16 & Memory read data. Latched when xxx. \\
sram\_byte\_we\_n   & out   & 2  & Memory byte write enable, active low.  \\
                    &       &    & (0) enables the low byte (7 downto 0) \\
                    &       &    & (1) enables the high byte (15 downto 8). \\
\midrule
io\_rd\_addr        & out   & 30 & I/O port read address (bits 1..0 absent). \\
                    &       &    & Only valid when io\_rd\_vma is high. \\
io\_wr\_addr        & out   & 30 & I/O port write address (bits 1..0 absent). \\
io\_wr\_data        & out   & 32 & I/O write data.  Only valid when one of the \\
                    &       &    & i/o byte write enable outputs is active.\\
io\_rd\_data        & in    & 32 & I/O read data. Latched when xxx. \\
io\_byte\_we        & out   & 4  & I/O byte write enable, active high. \\
                    &       &    & (0) enables the low byte (7 downto 0) \\
                    &       &    & (3) enables the high byte (31 downto 24). \\
io\_rd\_vma         & out   & 1  & Active high on i/o read cycles. \\
\midrule
uart\_rxd           & in    & 1  & RxD input to internal UART. \\
uart\_txd           & out   & 1  & TxD output from internal UART. \\
\midrule
interrupt           & in    & 8  & Interrupt request inputs, active high. \\
\bottomrule
\end{tabularx}
\end{table}
 
As you can see in figure~\ref{soc_symbol} (symbol generated by Xilinx ISE), 
the SoC has the following interfaces:
 
\begin{enumerate}
    \item Interface to external static asynchronous memory (SRAM, FLASH...).
    \item Interface to on-chip peripherals.
    \item Interrupt inputs.
    \item Debug port.
\end{enumerate}
 
These interfaces will be explained in the following subsections. The top module
for the demo supplied with the project (c2sb\_demo.vhdl) will be used for 
illustration.
 
\emph{NOTE}: This section needs a lot of elaboration -- ideally this should be 
equivalent to a datasheet in thoroughness and detail. This work, like many 
other parts of this project, will have to wait.
 
\subsection{SoC interface to static memory}
\label{soc_if_sram}
 
The interface to external memory in the SoC module is essentially that of the 
internal cache/memory controller. Its timing is described in section 
~\ref{cache_state_machine}.\\
 
The SoC inputs are meant to be connected straight to the FPGA i/o pins. The only
trick is the bidirectional memory data bus: as you can see, the SoC data buses 
are unidirectional and thus you will need to provide an interconnection
external to this module. This interconnection shall include the requisite 
3-state buffers:
 
\begin{verbatim}
sram_databus <= sram_data_wr when sram_byte_we_n/="11" else (others => 'Z');
\end{verbatim}
 
The top level \emph{c2sb\_demo} module can be used as a fully tested example of 
how to use this interface to connect to a common 16-bit-wide SRAM chip 
(ISSI IS61LV25616).
 
In reviewing the top module source, note that I had to adapt the dual 
byte-write-enable outputs to the SRAM
configuration of a single write-enable plus dual byte-enable inputs.
 
Note too that the static memory bus of the SoC module is used to access both the 16-bit wide SRAM 
and an 8-bit wide FLASH. These chips are connected to separate buses on the 
target board, so the top c2sb\_demo module needs to conflate both buses before connecting 
them to the SoC. This is why a multiplexor is used in the \texttt{mpu\_sram\_data\_rd}
bus. A real-world board would probably have the SRAM and the FLASH connected 
to the same bus, simplifying the interface logic.
 
 
\subsection{SoC interface to peripherals}
\label{soc_if_io}
 
    Every CPU access to an area designated as I/O (see ~\ref{soc_memory_map}, memory map)
    will trigger a read/write cycle on this interface.
 
    I/O ports are synchronous, byte accesible registers meant to be implemented
    within the FPGA. I/O ports do not support wait states.
 
    The I/O interface has separate input and output buses. 
 
    In an output cycle, one or more lines of signal \texttt{io\_byte\_we} will be
    asserted for one clock cycle. Signals \texttt{io\_wr\_addr} and \texttt{io\_wr\_addr} will
    be valid as long as \texttt{io\_byte\_we} is asserted.
 
    In an input cycle, \texttt{io\_rd\_vma} will be asserted for one cycle and the input
    data should be present at \texttt{io\_rd\_data} at the end of the following clock 
    cycle. The full read operation extends over two clock cycles.
 
\subsection{SoC interrupt inputs}
\label{soc_irqs}
 
    The present version of the CPU does not have support for hardware interrupts 
    and therefore these signals are not used yet and are unconnected. 
    Hardware interrupts will be implemented in some future version as 
    time permits.
 
\subsection{SoC debug port}
\label{soc_debug_port}
 
    The debug port is a VHDL record (\texttt{t\_debug\_info}, defined in 
    package \emph{mips\_pkg}), which holds some internal CPU status flags that 
    can be useful while debugging the core. It is not meant to be useful for 
    a real application.
 
    Currently the record holds only two flags:
 
    \begin{itemize}
    \item \texttt{cache\_enabled}, asserted when the cache is enabled.
    \item \texttt{unmapped\_access}, asserted when some access to an unmapped 
    address is made.
    \end{itemize}
 
    The current version of the demo connects these signals to some on-board 
    LEDs. 
 
 
\section{SoC Memory Map}
\label{soc_memory_map}    
 
    The \emph{memory map} determines the type of memory that is connected to 
    each of a number of predefined address rangess (see section 
    ~\ref{memory_map_definition}).
    It is defined in package \emph{mips\_pkg} and it is implemented in the 
    \emph{mips\_cache} module.
 
\begin{table}[h]
\caption{SoC module memory map\label{tab_soc_memory_map}}
\begin{tabularx}{\textwidth}{ lll|X }
\toprule
Address range & Type & Wait States & Intended usage \\
\midrule
\texttt{0xb8000000-0xbfffffff}   & BRAM    & 0  & SoC internal boot BRAM. \\
\midrule
\texttt{0x00000000-0x07ffffff}   & SRAM-16 & 2  & Off-chip SRAM. \\
\texttt{0x80000000-0x87ffffff}   & SRAM-16 & 2  & Off-chip SRAM. \\
\texttt{0x20000000-0x27ffffff}   & I/O     & 0  & On-chip I/O registers. \\
\texttt{0xb0000000-0xb7ffffff}   & SRAM-8  & 7  & Off-chip SRAM or FLASH. \\
\bottomrule
\end{tabularx}
\end{table}   
 
 
\section{SoC UART}
\label{soc_uart}    
 
    The current revision of the SoC includes a single peripheral, a hardwired 
    8-bit UART (file \emph{uart.vhdl}).
 
    This UART is an 8-bit module built for some other unrelated project of mine
    and commandeered to serve on this SoC. Therefore, it has some features
    (like its 8-bit interface) which are sub-optimal for this application and/or
    are not used.
 
    The UART is 'hardwired' because some of its operational parameters are 
    hardcoded and can't be changed even at synthesis time. Namely:
 
    \begin{itemize}
    \item Stop bits: 1.
    \item Parity: None.
    \item Bits per character: 8.
    \end{itemize}
 
    All other parameters can at least be configured at synthesis time, and 
    under some conditions can be configured at run time too. The interested 
    user must read the module source for a better explaination of these 
    features. This document will only deal with the UART module as it is 
    instantiated in the SoC.
 
 
    These are the UART control registers:
 
    \begin{table}[h]
    \caption{UART control registers\label{uart_control_regs}}
    \begin{tabularx}{\textwidth}{ ll|X }
    \toprule
    Byte Address & Word Address & Register \\
    \midrule
    \texttt{0x20000003}   & \texttt{0x20000000} & Tx/Rx Buffer \\
    \texttt{0x20000007}   & \texttt{0x20000004} & Status. \\
    \texttt{0x2000000b}   & \texttt{0x20000008} & Baud rate period, low byte. \\
    \texttt{0x2000000f}   & \texttt{0x2000000c} & Baud rate period, high byte. \\
    \bottomrule
    \end{tabularx}
    \end{table} 
 
 
    All of these registers are mapped to the byte address given in the table,
    that is, they are mapped on the \emph{low} byte of the 32-bit word they 
    belong to -- you don't have to worry about this unless you use a word 
    pointer to access these registers.
 
 
\subsection{UART Usage}
\label{soc_uart_usage}    
 
    Until hardware interrupts are implemented, you have to rely on polling to 
    use the UART.
 
    When you want to transmit, you wait until flag TxRdy is '1' and then write
    to the Tx Buffer. That will clear TxRdy until the transmission is done. 
    Writing to the Tx Buffer will NOT clear flag TxIrq. 
 
    Writing to the Tx Buffer while TxRdy is '0' will have no effect.
 
    When you want to read received data, you wait until RxRdy is '1' and then 
    read the Rx Buffer. Reading the Rx Buffer will clear flag RxRdy until a new 
    byte arrives.
    Reading the RxBuffer while RxRdy is '0' will return undefined data.
    Reading the Rx Buffer will NOT clear flag RxIrq.
 
    Of course, once hardware interrupts are implemented, you will use them 
    instead of polling, but this is the basic mechanics. Same as any old UART, 
    really.
 
 
 
\subsection{UART Status Register}
\label{soc_status_reg}    
 
    These are the flags present in the status register:
 
 
\needspace{7\baselineskip}    
\begin{verbatim}
  UART Status Register
 
      7       6       5       4       3       2       1       0
  +-------+-------+-------+-------+-------+-------+-------+-------+
  |   0   |   0   | RxIrq | TxIrq |   0   |   0   | RxRdy | TxRdy |
  +-------+-------+-------+-------+-------+-------+-------+-------+
      h       h      W1C     W1C      h       h       r       r     
\end{verbatim}
 
 
    Bits marked 'h' are hardwired and can't be modified. 
 
    Bits marked 'r' are read only; they are set and clear by the UART core.
 
    Bits marked W1C ('Write 1 Clear') are set by the UART core when an interrupt 
    has been triggered and must be cleared by the software by writing a '1'.
 
    \begin{itemize}
    \item Status bit TxRdy is high when there isn't any transmission in progress. 
            It is cleared when data is written to the transmission buffer and is 
            raised at the same time the transmission interrupt is triggered.
    \item Status bit RxRdy is raised at the same time the receive interrupt is
            triggered and is cleared when the data register is read.
    \item Status bit TxIrq is raised when the transmission interrupt is triggered 
            and is cleared when a 1 is written to it.
    \item Status bit RxIrq is raised when the reception interrupt is triggered 
            and is cleared when a 1 is written to it.
    \end{itemize}
 
    When writing to the status/control registers, only flags TxIrq and RxIrq are
    affected, and only when writing a '1' as explained above. All other flags 
    are read-only.
 
 
\subsection{UART Baud Rate Registers}
\label{soc_uart_baud_regs}    
 
    When the UART module generic 'HARDWIRED' is set to 'false', these registers
    can be written to in order to configure the baud rate -- see the source for 
    details.
 
    When the UART module generic 'HARDWIRED' is set to 'true', these registers
    are frozen and can't be modified. This is how the module is instantiated in 
    the current version of the SoC.
 
    In either case, these are write-only registers: reading them will return 
    the contents of the status register (simplified multiplexor).
 
    The baud rate is configured by loading these registers with the baud period
    in clock cycles.
 
 
\subsection{UART Interrupt}
\label{soc_uart_interrupts}    
 
    The UART can trigger an interrupt (i.e. assert its interrupt output for one 
    clock cycle) whenever a character is received or transmitted. The UART
    source explains in detail exactly when these interrupts are triggered.
 
    The interrupt status is kept in two flags on the status register that can 
    be used for interrupt polling. Note there's no way to tell what kind of
    interrupt we got other than looking at those flags.
 
    Since the current CPU revision does not support hardware interrupts, this
    feature is still unused and the interrupt line is unconnected.
    Again, details can be found in the UART module source.
 
 
 
 
 
 
 
 
 
 
 
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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