Skip to content

Commit

Permalink
Merge branch 'release-1.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
catharanthus committed Aug 28, 2022
2 parents 2929656 + a53f464 commit 984250e
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 55 deletions.
Binary file modified doc/lxp32-trm.pdf
Binary file not shown.
4 changes: 2 additions & 2 deletions doc/src/trm/frontmatter.tex
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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:

Expand Down
25 changes: 18 additions & 7 deletions doc/src/trm/lxp32-trm.tex
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ \section{Interrupt handling}

\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}
Expand All @@ -241,19 +241,19 @@ \subsection{Control register}
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.

Expand All @@ -263,6 +263,12 @@ \subsection{Invoking interrupt handlers}

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:
Expand Down Expand Up @@ -494,6 +500,7 @@ \section{WISHBONE data bus}
\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.

Expand Down Expand Up @@ -1105,7 +1112,7 @@ \subsubsection{Operation}
\subsection{\instr{hlt} -- Halt}
\label{subsec:instr:hlt}

Wait for an interrupt.
Halt the CPU until an enabled interrupt is received.

\subsubsection{Syntax}

Expand Down Expand Up @@ -1828,6 +1835,10 @@ \section{Data bus}

\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.
Expand Down
5 changes: 5 additions & 0 deletions rtl/lxp32_cpu.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ signal interrupt_valid: std_logic;
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

Expand Down Expand Up @@ -131,6 +132,8 @@ decode_inst: entity work.lxp32_decode(rtl)
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,
Expand Down Expand Up @@ -247,6 +250,8 @@ interrupt_mux_inst: entity work.lxp32_interrupt_mux(rtl)
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,
Expand Down
8 changes: 7 additions & 1 deletion rtl/lxp32_decode.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ entity lxp32_decode is
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);
Expand Down Expand Up @@ -100,6 +102,7 @@ signal rd2_direct: std_logic_vector(31 downto 0);
-- Signals related to interrupt handling

signal interrupt_ready: std_logic:='0';
signal wakeup_reg: std_logic:='0';

begin

Expand Down Expand Up @@ -148,8 +151,10 @@ begin
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';
Expand Down Expand Up @@ -257,6 +262,7 @@ begin
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';
Expand Down Expand Up @@ -285,7 +291,7 @@ begin
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;
Expand Down
23 changes: 15 additions & 8 deletions rtl/lxp32_interrupt_mux.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ entity lxp32_interrupt_mux is
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;
Expand All @@ -43,15 +45,13 @@ signal pending_interrupts: std_logic_vector(irq_i'range):=(others=>'0');
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
Expand All @@ -62,17 +62,18 @@ begin
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));
Expand All @@ -90,6 +91,12 @@ begin
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;
Expand All @@ -101,10 +108,10 @@ begin
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;
Expand Down
51 changes: 16 additions & 35 deletions verify/lxp32/src/firmware/test016.asm
Original file line number Diff line number Diff line change
@@ -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 iv0, timer_handler
lc cr, 0x101 // enable interrupt 0 in temporarily blocked state
lc r32, 0 // interrupt handler call counter
lc r33, 1000 // loop counter
lc r34, loop1
lc r35, loop2
sw r104, 100
sw r103, 1
lc r102, 0x30000000 // coprocessor input register
lc r103, 0x30000004 // coprocessor output register
lc r104, failure

loop1:
sub r33, r33, 1
cjmpug r34, r33, 0 // loop1
lc r33, 1000
mov cr, 1 // unblock interrupt 0
lcs cr, 0x0404 // enable coprocessor interrupt and mark it as wake-up
loop2:
sub r33, r33, 1
cjmpug r35, r33, 0 // loop2
sw r102, 33
// r32 should be 1 by this point
cjmpne r102, r32, 1 // failure
sw r100, 1
hlt

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
4 changes: 2 additions & 2 deletions verify/lxp32/src/platform/coprocessor.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ architecture rtl of coprocessor is

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
Expand Down Expand Up @@ -67,7 +67,7 @@ begin
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;
Expand Down

0 comments on commit 984250e

Please sign in to comment.