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

Subversion Repositories lxp32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 11 to Rev 12
    Reverse comparison

Rev 11 → Rev 12

/lxp32/trunk/doc/lxp32-trm.pdf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/lxp32/trunk/doc/src/trm/frontmatter.tex
15,7 → 15,7
\Large a lightweight open source 32-bit CPU core\par
\LARGE \textbf{Technical Reference Manual}\par
\vspace{1.2\onelineskip}
\large Version 1.2\par
\large Version 1.3\par
\vspace*{4\onelineskip}
\end{center}
\vspace*{\fill}
34,7 → 34,7
 
\vspace*{\fill}
 
Copyright \textcopyright{} 2016--2019 by Alex I. Kuznetsov.
Copyright \textcopyright{} 2016--2022 by Alex I. Kuznetsov.
 
The entire \lxp{} IP core package, including the synthesizable RTL description, verification environment, documentation and software tools, is distributed under the terms of the MIT license reproduced below:
 
/lxp32/trunk/doc/src/trm/lxp32-trm.tex
231,7 → 231,7
 
\subsection{Control register}
 
\lxp{} supports 8 interrupts with hardwired priority levels (interrupts with lower vector numbers have higher priority). Interrupts vectors (pointers to interrupt handlers) are stored in the \code{iv0}--\code{iv7} registers. Interrupt handling is controlled by the \code{cr} register (Table \ref{tab:cr}).
\lxp{} supports 8 interrupts with hardwired priority levels (interrupts with lower vector numbers have higher priority). Interrupt vectors (pointers to interrupt handlers) are stored in the \code{iv0}--\code{iv7} registers. Interrupt handling is controlled by the \code{cr} register (Table \ref{tab:cr}).
 
\begin{table}[htbp]
\caption{Control register}
241,20 → 241,20
Bit & Description \\
\midrule
0 & Enable interrupt 0 \\
1 & Enable interrupt 1 \\
& \ldots \\
7 & Enable interrupt 7 \\
8 & Temporarily block interrupt 0 \\
9 & Temporarily block interrupt 1 \\
8 & Interrupt 0 wake-up flag \\
& \ldots \\
15 & Temporarily block interrupt 7 \\
15 & Interrupt 7 wake-up flag \\
31--16 & \emph{Reserved} \\
\bottomrule
\end{tabularx}
\end{table}
 
Disabled interrupts are ignored altogether: if the CPU receives an interrupt request signal while the corresponding interrupt is disabled, the interrupt handler will not be called even if the interrupt is enabled later. Conversely, temporarily blocked interrupts are still registered, but their handlers are not called until they are unblocked.
Disabled interrupts are ignored altogether: if the CPU receives an interrupt request signal while the corresponding interrupt is disabled, the interrupt will not be processed even if it is enabled later.
 
Wake-up flag marks the interrupt as a \emph{wake-up interrupt} (see below).
 
Like other registers, \code{cr} is zero-initialized during the CPU reset, meaning that no interrupts are initially enabled.
 
\subsection{Invoking interrupt handlers}
263,6 → 263,12
 
An interrupt handler returns using the \code{\instr{jmp} irp} instruction which also has an \instr{iret} alias. Until the interrupt handler returns, the CPU will defer further interrupt processing (although incoming interrupt requests will still be registered). This also means that the \code{irp} register value will not be unexpectedly overwritten. When executing the \code{\instr{jmp} irp} instruction, the CPU will recognize the \code{IRF} flag and resume interrupt processing as usual. It is also possible to perform a conditional return from the interrupt handler, similarly to the technique described in Section \ref{sec:callingprocedures} for conditional procedure returns.
 
\subsection{Wake-up interrupts}
 
When a wake-up interrupt is received, the interrupt handler is not called, but the CPU still resumes execution if halted by the \instr{hlt} instruction. The effect is similar to invoking an interrupt with an empty handler (containing only \instr{iret}), but without the overhead of interrupt processing. Wake-up interrupts do not affect the CPU when it is not halted.
 
Unlike normal interrupts, wake-up interrupts are processed even when the CPU executes an interrupt handler for another interrupt.
 
\subsection{Non-returnable interrupts}
 
If an interrupt vector has the least significant bit (\code{IRF}) set, the CPU will resume interrupt processing immediately. One should not try to invoke \instr{iret} from such a handler since the \code{irp} register could have been overwritten by another interrupt. This technique can be useful when the CPU's only task is to process external events:
494,6 → 500,7
\end{figure}
 
\section{Interrupts}
\label{sec:interrupts}
 
\lxp{} registers an interrupt condition when the corresponding request signal goes from \code{0} to \code{1}. Transitions from \code{1} to \code{0} are ignored. All interrupt request signals must be synchronous with the system clock (\signal{clk\_i}); if coming from an asynchronous source, they must be synchronized using a sequence of at least two flip-flops clocked by \signal{clk\_i}. These flip-flops are not included in the \lxp{} core in order not to increase interrupt processing delay for interrupt sources that are inherently synchronous. Failure to properly synchronize interrupt request signals will cause timing violations that will manifest itself as intermittent, hard to debug faults.
 
1105,7 → 1112,7
\subsection{\instr{hlt} -- Halt}
\label{subsec:instr:hlt}
 
Wait for an interrupt.
Halt the CPU until an enabled interrupt is received.
 
\subsubsection{Syntax}
 
1828,6 → 1835,10
 
\chapter{List of changes}
 
\section*{Version 1.3 (2022-08-28)}
 
This release removes support for temporarily blocked interrupts (interrupts can still be disabled) and introduces wake-up interrupts.
 
\section*{Version 1.2 (2021-10-21)}
 
This release introduces a few non-breaking changes to the software and testbench. The CPU RTL description hasn't been changed from the previous release.
/lxp32/trunk/rtl/lxp32_cpu.vhd
89,6 → 89,7
signal interrupt_vector: std_logic_vector(2 downto 0);
signal interrupt_ready: std_logic;
signal interrupt_return: std_logic;
signal interrupt_wakeup: std_logic;
 
begin
 
131,6 → 132,8
interrupt_valid_i=>interrupt_valid,
interrupt_vector_i=>interrupt_vector,
interrupt_ready_o=>interrupt_ready,
 
wakeup_i=>interrupt_wakeup,
sp_raddr1_o=>sp_raddr1,
sp_rdata1_i=>sp_rdata1,
247,6 → 250,8
interrupt_vector_o=>interrupt_vector,
interrupt_ready_i=>interrupt_ready,
interrupt_return_i=>interrupt_return,
 
wakeup_o=>interrupt_wakeup,
sp_waddr_i=>sp_waddr,
sp_we_i=>sp_we,
/lxp32/trunk/rtl/lxp32_decode.vhd
27,6 → 27,8
interrupt_valid_i: in std_logic;
interrupt_vector_i: in std_logic_vector(2 downto 0);
interrupt_ready_o: out std_logic;
 
wakeup_i: in std_logic;
sp_raddr1_o: out std_logic_vector(7 downto 0);
sp_rdata1_i: in std_logic_vector(31 downto 0);
100,6 → 102,7
-- Signals related to interrupt handling
 
signal interrupt_ready: std_logic:='0';
signal wakeup_reg: std_logic:='0';
 
begin
 
148,8 → 151,10
op3_o<=(others=>'-');
jump_type_o<=(others=>'-');
dst_out<=(others=>'-');
wakeup_reg<='0';
else
interrupt_ready<='0';
wakeup_reg<=wakeup_reg or wakeup_i;
if jump_valid_i='1' then
valid_out<='0';
self_busy<='0';
257,6 → 262,7
elsif opcode="000010" then
valid_out<='0';
self_busy<='1';
wakeup_reg<='0';
state<=Halt;
elsif opcode(5 downto 4)="11" then
valid_out<='1';
285,7 → 291,7
when ContinueInterrupt =>
valid_out<='0';
when Halt =>
if interrupt_valid_i='1' then
if interrupt_valid_i='1' or wakeup_i='1' or wakeup_reg='1' then
self_busy<='0';
state<=Regular;
end if;
/lxp32/trunk/rtl/lxp32_interrupt_mux.vhd
24,6 → 24,8
interrupt_vector_o: out std_logic_vector(2 downto 0);
interrupt_ready_i: in std_logic;
interrupt_return_i: in std_logic;
 
wakeup_o: out std_logic;
sp_waddr_i: in std_logic_vector(7 downto 0);
sp_we_i: in std_logic;
43,15 → 45,13
signal interrupt_valid: std_logic:='0';
 
signal interrupts_enabled: std_logic_vector(7 downto 0):=(others=>'0');
signal interrupts_blocked: std_logic_vector(7 downto 0):=(others=>'0');
signal interrupts_wakeup: std_logic_vector(7 downto 0):=(others=>'0');
 
begin
 
-- Note: "disabled" interrupts (i.e. for which interrupts_enabled_i(i)='0')
-- are ignored completely, meaning that the interrupt handler won't be
-- called even if the interrupt is enabled later. Conversely, "blocked"
-- interrupts are registered, but their handlers are not called until they
-- are unblocked.
-- called even if the interrupt is enabled later.
 
process (clk_i) is
begin
62,17 → 62,18
state<=Ready;
interrupt_valid<='0';
interrupt_vector_o<=(others=>'-');
wakeup_o<='0';
else
irq_reg<=irq_i;
pending_interrupts<=(pending_interrupts or
(irq_i and not irq_reg)) and
interrupts_enabled;
interrupts_enabled and not interrupts_wakeup;
case state is
when Ready =>
for i in pending_interrupts'reverse_range loop -- lower interrupts have priority
if pending_interrupts(i)='1' and interrupts_blocked(i)='0' then
if pending_interrupts(i)='1' then
pending_interrupts(i)<='0';
interrupt_valid<='1';
interrupt_vector_o<=std_logic_vector(to_unsigned(i,3));
90,6 → 91,12
state<=Ready;
end if;
end case;
 
if (irq_i and (not irq_reg) and interrupts_enabled and interrupts_wakeup)/=X"00" then
wakeup_o<='1';
else
wakeup_o<='0';
end if;
end if;
end if;
end process;
101,10 → 108,10
if rising_edge(clk_i) then
if rst_i='1' then
interrupts_enabled<=(others=>'0');
interrupts_blocked<=(others=>'0');
interrupts_wakeup<=(others=>'0');
elsif sp_we_i='1' and sp_waddr_i=X"FC" then
interrupts_enabled<=sp_wdata_i(7 downto 0);
interrupts_blocked<=sp_wdata_i(15 downto 8);
interrupts_wakeup<=sp_wdata_i(15 downto 8);
end if;
end if;
end process;
/lxp32/trunk/tools/bin/lxp32asm.exe Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/lxp32/trunk/tools/bin/lxp32dump.exe Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/lxp32/trunk/tools/bin/wigen.exe Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
/lxp32/trunk/verify/lxp32/src/firmware/test016.asm
1,47 → 1,28
/*
* Test for temporarily blocked interrupts
* Test wake-up interrupts
*/
 
lc r100, 0x10000000 // test result output pointer
lc r101, halt
lc r102, failure
lc r103, 0x20000000 // timer: number of pulses (0xFFFFFFFF - infinite)
lc r104, 0x20000004 // timer: delay between pulses (in cycles)
lc r102, 0x30000000 // coprocessor input register
lc r103, 0x30000004 // coprocessor output register
lc r104, failure
 
lcs cr, 0x0404 // enable coprocessor interrupt and mark it as wake-up
lc iv0, timer_handler
lc cr, 0x101 // enable interrupt 0 in temporarily blocked state
sw r102, 33
lc r32, 0 // interrupt handler call counter
lc r33, 1000 // loop counter
lc r34, loop1
lc r35, loop2
sw r104, 100
sw r103, 1
hlt
 
loop1:
sub r33, r33, 1
cjmpug r34, r33, 0 // loop1
lc r33, 1000
mov cr, 1 // unblock interrupt 0
loop2:
sub r33, r33, 1
cjmpug r35, r33, 0 // loop2
// r32 should be 1 by this point
cjmpne r102, r32, 1 // failure
sw r100, 1
lw r1, r103
cjmpne r104, r1, 99
 
sw r100, 1 // success
 
halt:
hlt
jmp r101 // halt
 
failure:
sw r100, 2
halt:
hlt
jmp r101 // halt
timer_handler:
add r32, r32, 1
iret
/lxp32/trunk/verify/lxp32/src/platform/coprocessor.vhd
38,7 → 38,7
 
signal value: unsigned(31 downto 0):=(others=>'0');
signal result: unsigned(31 downto 0):=(others=>'0');
signal cnt: integer range 0 to 5:=0;
signal cnt: integer range 0 to 50:=0;
signal irq: std_logic:='0';
 
begin
67,7 → 67,7
if wbs_adr_i="00"&X"000000" then
value(i*8+7 downto i*8)<=
unsigned(wbs_dat_i(i*8+7 downto i*8));
cnt<=5;
cnt<=50;
end if;
end if;
end loop;

powered by: WebSVN 2.1.0

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