diff --git a/.gitmodules b/.gitmodules
index df2166d3a8dd621fab4365e9cd0cc8502c410496..9928787c6a9a1ee668c29a4e61c9258fc23dab22 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -46,3 +46,6 @@
 [submodule "src/rv_plic"]
 	path = src/rv_plic
 	url = https://github.com/pulp-platform/rv_plic.git
+[submodule "fpga/src/apb_timer"]
+	path = fpga/src/apb_timer
+	url = https://github.com/pulp-platform/apb_timer.git
diff --git a/Bender.yml b/Bender.yml
index 727892f56479372d16192ec79c78f0d9243d65f4..8dfe9e1f10c58344f9f60bbccbe12c720eb5c425 100644
--- a/Bender.yml
+++ b/Bender.yml
@@ -111,6 +111,8 @@ sources:
     - fpga/src/axi_slice/src/axi_ar_buffer.sv
     - fpga/src/axi_slice/src/axi_r_buffer.sv
     - fpga/src/axi_slice/src/axi_aw_buffer.sv
+    - fpga/src/apb_timer/apb_timer.sv
+    - fpga/src/apb_timer/timer.sv
     - src/axi_node/src/axi_regs_top.sv
     - src/axi_node/src/axi_BR_allocator.sv
     - src/axi_node/src/axi_BW_allocator.sv
diff --git a/Makefile b/Makefile
index 9693a5fc6a61d81a8221e51056ee4065054bdf11..0957459c1da580f5bd2e85c344e0bbfc9d5df590 100644
--- a/Makefile
+++ b/Makefile
@@ -131,6 +131,7 @@ src :=  $(filter-out src/ariane_regfile.sv, $(wildcard src/*.sv))              \
         $(wildcard bootrom/*.sv)                                               \
         $(wildcard src/clint/*.sv)                                             \
         $(wildcard fpga/src/axi2apb/src/*.sv)                                  \
+        $(wildcard fpga/src/apb_timer/*.sv)                                    \
         $(wildcard fpga/src/axi_slice/src/*.sv)                                \
         $(wildcard src/axi_node/src/*.sv)                                      \
         $(wildcard src/axi_riscv_atomics/src/*.sv)                             \
diff --git a/bootrom/ariane.dts b/bootrom/ariane.dts
index 9cd2df99f297c62372f2e8d2d0cc464ae2309431..54c9af0e6a507a73db6847d1d84c097d7c618777 100644
--- a/bootrom/ariane.dts
+++ b/bootrom/ariane.dts
@@ -68,5 +68,12 @@
       reg-shift = <2>; // regs are spaced on 32 bit boundary
       reg-io-width = <4>; // only 32-bit access are supported
     };
+    timer@18000000 {
+      compatible = "pulp,apb_timer";
+      interrupts = <0x00000004 0x00000005 0x00000006 0x00000007>;
+      reg = <0x00000000 0x18000000 0x00000000 0x00001000>;
+      // interrupt-parent = <&PLIC0>;
+      reg-names = "control";
+    };
   };
 };
diff --git a/fpga/src/apb_timer b/fpga/src/apb_timer
new file mode 160000
index 0000000000000000000000000000000000000000..6c84f69d2e92bd766f609b5dd47ece723359bd24
--- /dev/null
+++ b/fpga/src/apb_timer
@@ -0,0 +1 @@
+Subproject commit 6c84f69d2e92bd766f609b5dd47ece723359bd24
diff --git a/fpga/src/ariane_peripherals_xilinx.sv b/fpga/src/ariane_peripherals_xilinx.sv
index 55ee73c1eff2fce9de52ade1a9fce3465f93754e..06501847952a9baa36a899e0e7c4bcd1f9f6e788 100644
--- a/fpga/src/ariane_peripherals_xilinx.sv
+++ b/fpga/src/ariane_peripherals_xilinx.sv
@@ -18,7 +18,8 @@ module ariane_peripherals #(
     parameter bit InclUART     = 1,
     parameter bit InclSPI      = 0,
     parameter bit InclEthernet = 0,
-    parameter bit InclGPIO     = 0
+    parameter bit InclGPIO     = 0,
+    parameter bit InclTimer    = 1
 ) (
     input  logic       clk_i           , // Clock
     input  logic       clk_200MHz_i    ,
@@ -28,6 +29,7 @@ module ariane_peripherals #(
     AXI_BUS.Slave      spi             ,
     AXI_BUS.Slave      gpio            ,
     AXI_BUS.Slave      ethernet        ,
+    AXI_BUS.Slave      timer           ,
     output logic [1:0] irq_o           ,
     // UART
     input  logic       rx_i            ,
@@ -732,4 +734,99 @@ module ariane_peripherals #(
         assign s_axi_gpio_rlast = 1'b1;
         assign s_axi_gpio_wlast = 1'b1;
     end
+
+    // 6. Timer
+    if (InclTimer) begin : gen_timer
+        logic         timer_penable;
+        logic         timer_pwrite;
+        logic [31:0]  timer_paddr;
+        logic         timer_psel;
+        logic [31:0]  timer_pwdata;
+        logic [31:0]  timer_prdata;
+        logic         timer_pready;
+        logic         timer_pslverr;
+
+        axi2apb_64_32 #(
+            .AXI4_ADDRESS_WIDTH ( AxiAddrWidth ),
+            .AXI4_RDATA_WIDTH   ( AxiDataWidth ),
+            .AXI4_WDATA_WIDTH   ( AxiDataWidth ),
+            .AXI4_ID_WIDTH      ( AxiIdWidth   ),
+            .AXI4_USER_WIDTH    ( AxiUserWidth ),
+            .BUFF_DEPTH_SLAVE   ( 2            ),
+            .APB_ADDR_WIDTH     ( 32           )
+        ) i_axi2apb_64_32_timer (
+            .ACLK      ( clk_i           ),
+            .ARESETn   ( rst_ni          ),
+            .test_en_i ( 1'b0            ),
+            .AWID_i    ( timer.aw_id     ),
+            .AWADDR_i  ( timer.aw_addr   ),
+            .AWLEN_i   ( timer.aw_len    ),
+            .AWSIZE_i  ( timer.aw_size   ),
+            .AWBURST_i ( timer.aw_burst  ),
+            .AWLOCK_i  ( timer.aw_lock   ),
+            .AWCACHE_i ( timer.aw_cache  ),
+            .AWPROT_i  ( timer.aw_prot   ),
+            .AWREGION_i( timer.aw_region ),
+            .AWUSER_i  ( timer.aw_user   ),
+            .AWQOS_i   ( timer.aw_qos    ),
+            .AWVALID_i ( timer.aw_valid  ),
+            .AWREADY_o ( timer.aw_ready  ),
+            .WDATA_i   ( timer.w_data    ),
+            .WSTRB_i   ( timer.w_strb    ),
+            .WLAST_i   ( timer.w_last    ),
+            .WUSER_i   ( timer.w_user    ),
+            .WVALID_i  ( timer.w_valid   ),
+            .WREADY_o  ( timer.w_ready   ),
+            .BID_o     ( timer.b_id      ),
+            .BRESP_o   ( timer.b_resp    ),
+            .BVALID_o  ( timer.b_valid   ),
+            .BUSER_o   ( timer.b_user    ),
+            .BREADY_i  ( timer.b_ready   ),
+            .ARID_i    ( timer.ar_id     ),
+            .ARADDR_i  ( timer.ar_addr   ),
+            .ARLEN_i   ( timer.ar_len    ),
+            .ARSIZE_i  ( timer.ar_size   ),
+            .ARBURST_i ( timer.ar_burst  ),
+            .ARLOCK_i  ( timer.ar_lock   ),
+            .ARCACHE_i ( timer.ar_cache  ),
+            .ARPROT_i  ( timer.ar_prot   ),
+            .ARREGION_i( timer.ar_region ),
+            .ARUSER_i  ( timer.ar_user   ),
+            .ARQOS_i   ( timer.ar_qos    ),
+            .ARVALID_i ( timer.ar_valid  ),
+            .ARREADY_o ( timer.ar_ready  ),
+            .RID_o     ( timer.r_id      ),
+            .RDATA_o   ( timer.r_data    ),
+            .RRESP_o   ( timer.r_resp    ),
+            .RLAST_o   ( timer.r_last    ),
+            .RUSER_o   ( timer.r_user    ),
+            .RVALID_o  ( timer.r_valid   ),
+            .RREADY_i  ( timer.r_ready   ),
+            .PENABLE   ( timer_penable   ),
+            .PWRITE    ( timer_pwrite    ),
+            .PADDR     ( timer_paddr     ),
+            .PSEL      ( timer_psel      ),
+            .PWDATA    ( timer_pwdata    ),
+            .PRDATA    ( timer_prdata    ),
+            .PREADY    ( timer_pready    ),
+            .PSLVERR   ( timer_pslverr   )
+        );
+
+        apb_timer #(
+                .APB_ADDR_WIDTH ( 32 ),
+                .TIMER_CNT      ( 2  )
+        ) i_timer (
+            .HCLK    ( clk_i            ),
+            .HRESETn ( rst_ni           ),
+            .PSEL    ( timer_psel       ),
+            .PENABLE ( timer_penable    ),
+            .PWRITE  ( timer_pwrite     ),
+            .PADDR   ( timer_paddr      ),
+            .PWDATA  ( timer_pwdata     ),
+            .PRDATA  ( timer_prdata     ),
+            .PREADY  ( timer_pready     ),
+            .PSLVERR ( timer_pslverr    ),
+            .irq_o   ( irq_sources[6:3] )
+        );
+    end
 endmodule
diff --git a/fpga/src/ariane_xilinx.sv b/fpga/src/ariane_xilinx.sv
index c895d8c8c8d36571473e88ee2ba80b268840dd34..f633d62202da2dce411744e0f626590f04e35b78 100644
--- a/fpga/src/ariane_xilinx.sv
+++ b/fpga/src/ariane_xilinx.sv
@@ -269,6 +269,7 @@ axi_node_wrap_with_slices #(
         ariane_soc::CLINTBase,
         ariane_soc::PLICBase,
         ariane_soc::UARTBase,
+        ariane_soc::TimerBase,
         ariane_soc::SPIBase,
         ariane_soc::EthernetBase,
         ariane_soc::GPIOBase,
@@ -280,6 +281,7 @@ axi_node_wrap_with_slices #(
         ariane_soc::CLINTBase    + ariane_soc::CLINTLength - 1,
         ariane_soc::PLICBase     + ariane_soc::PLICLength - 1,
         ariane_soc::UARTBase     + ariane_soc::UARTLength - 1,
+        ariane_soc::TimerBase    + ariane_soc::TimerLength - 1,
         ariane_soc::SPIBase      + ariane_soc::SPILength - 1,
         ariane_soc::EthernetBase + ariane_soc::EthernetLength -1,
         ariane_soc::GPIOBase     + ariane_soc::GPIOLength - 1,
@@ -534,6 +536,7 @@ ariane_peripherals #(
     .gpio         ( master[ariane_soc::GPIO]     ),
     .eth_clk_i    ( eth_clk                      ),
     .ethernet     ( master[ariane_soc::Ethernet] ),
+    .timer        ( master[ariane_soc::Timer]    ),
     .irq_o        ( irq                          ),
     .rx_i         ( rx                           ),
     .tx_o         ( tx                           ),
diff --git a/fpga/src/bootrom/ariane.dts b/fpga/src/bootrom/ariane.dts
index 59ee3341a7c04edcdcfa984fcd11d52e2c560b03..0f0e943496a48bd1fbf30d7b5c9cf832a7fc1bf1 100644
--- a/fpga/src/bootrom/ariane.dts
+++ b/fpga/src/bootrom/ariane.dts
@@ -60,7 +60,7 @@
       interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>;
       reg = <0x0 0xc000000 0x0 0x4000000>;
       riscv,max-priority = <7>;
-      riscv,ndev = <3>;
+      riscv,ndev = <30>;
     };
     debug-controller@0 {
       compatible = "riscv,debug-013";
@@ -78,6 +78,13 @@
       reg-shift = <2>; // regs are spaced on 32 bit boundary
       reg-io-width = <4>; // only 32-bit access are supported
     };
+    timer@18000000 {
+      compatible = "pulp,apb_timer";
+      interrupts = <0x00000004 0x00000005 0x00000006 0x00000007>;
+      reg = <0x00000000 0x18000000 0x00000000 0x00001000>;
+      interrupt-parent = <&PLIC0>;
+      reg-names = "control";
+    };
     xps-spi@20000000 {
       compatible = "xlnx,xps-spi-2.00.b", "xlnx,xps-spi-2.00.a";
       #address-cells = <1>;
diff --git a/src_files.yml b/src_files.yml
index a5e7fd259d005e4140c56950faf4ab5f4acf2220..0a150f3aa1493e40a849dd49565e314923a0454c 100644
--- a/src_files.yml
+++ b/src_files.yml
@@ -54,6 +54,8 @@ ariane:
     src/debug/dmi_cdc.sv,
     src/debug/dmi_jtag.sv,
     src/debug/dmi_jtag_tap.sv,
+    fpga/apb_timer/apb_timer.sv,
+    fpga/apb_timer/timer.sv,
     ]
 riscv_regfile_rtl:
   targets: [
diff --git a/tb/ariane_peripherals.sv b/tb/ariane_peripherals.sv
index 13ec46f38e67bcf57e70e1a8effe7ee7eef33e69..9f9f76c425ffc6700aa084d97d306b1f77878e24 100644
--- a/tb/ariane_peripherals.sv
+++ b/tb/ariane_peripherals.sv
@@ -17,7 +17,8 @@ module ariane_peripherals #(
     parameter bit InclUART     = 1,
     parameter bit InclSPI      = 0,
     parameter bit InclEthernet = 0,
-    parameter bit InclGPIO     = 0
+    parameter bit InclGPIO     = 0,
+    parameter bit InclTimer    = 1
 ) (
     input  logic       clk_i           , // Clock
     input  logic       rst_ni          , // Asynchronous reset active low
@@ -25,6 +26,7 @@ module ariane_peripherals #(
     AXI_BUS.Slave      uart            ,
     AXI_BUS.Slave      spi             ,
     AXI_BUS.Slave      ethernet        ,
+    AXI_BUS.Slave      timer           ,
     output logic [1:0] irq_o           ,
     // UART
     input  logic       rx_i            ,
@@ -515,4 +517,101 @@ module ariane_peripherals #(
         assign ethernet.r_data = 'hdeadbeef;
         assign ethernet.r_last = 1'b1;
     end
+
+    // ---------------
+    // 5. Timer
+    // ---------------
+    if (InclTimer) begin : gen_timer
+        logic         timer_penable;
+        logic         timer_pwrite;
+        logic [31:0]  timer_paddr;
+        logic         timer_psel;
+        logic [31:0]  timer_pwdata;
+        logic [31:0]  timer_prdata;
+        logic         timer_pready;
+        logic         timer_pslverr;
+
+        axi2apb_64_32 #(
+            .AXI4_ADDRESS_WIDTH ( AxiAddrWidth ),
+            .AXI4_RDATA_WIDTH   ( AxiDataWidth ),
+            .AXI4_WDATA_WIDTH   ( AxiDataWidth ),
+            .AXI4_ID_WIDTH      ( AxiIdWidth   ),
+            .AXI4_USER_WIDTH    ( AxiUserWidth ),
+            .BUFF_DEPTH_SLAVE   ( 2            ),
+            .APB_ADDR_WIDTH     ( 32           )
+        ) i_axi2apb_64_32_timer (
+            .ACLK      ( clk_i           ),
+            .ARESETn   ( rst_ni          ),
+            .test_en_i ( 1'b0            ),
+            .AWID_i    ( timer.aw_id     ),
+            .AWADDR_i  ( timer.aw_addr   ),
+            .AWLEN_i   ( timer.aw_len    ),
+            .AWSIZE_i  ( timer.aw_size   ),
+            .AWBURST_i ( timer.aw_burst  ),
+            .AWLOCK_i  ( timer.aw_lock   ),
+            .AWCACHE_i ( timer.aw_cache  ),
+            .AWPROT_i  ( timer.aw_prot   ),
+            .AWREGION_i( timer.aw_region ),
+            .AWUSER_i  ( timer.aw_user   ),
+            .AWQOS_i   ( timer.aw_qos    ),
+            .AWVALID_i ( timer.aw_valid  ),
+            .AWREADY_o ( timer.aw_ready  ),
+            .WDATA_i   ( timer.w_data    ),
+            .WSTRB_i   ( timer.w_strb    ),
+            .WLAST_i   ( timer.w_last    ),
+            .WUSER_i   ( timer.w_user    ),
+            .WVALID_i  ( timer.w_valid   ),
+            .WREADY_o  ( timer.w_ready   ),
+            .BID_o     ( timer.b_id      ),
+            .BRESP_o   ( timer.b_resp    ),
+            .BVALID_o  ( timer.b_valid   ),
+            .BUSER_o   ( timer.b_user    ),
+            .BREADY_i  ( timer.b_ready   ),
+            .ARID_i    ( timer.ar_id     ),
+            .ARADDR_i  ( timer.ar_addr   ),
+            .ARLEN_i   ( timer.ar_len    ),
+            .ARSIZE_i  ( timer.ar_size   ),
+            .ARBURST_i ( timer.ar_burst  ),
+            .ARLOCK_i  ( timer.ar_lock   ),
+            .ARCACHE_i ( timer.ar_cache  ),
+            .ARPROT_i  ( timer.ar_prot   ),
+            .ARREGION_i( timer.ar_region ),
+            .ARUSER_i  ( timer.ar_user   ),
+            .ARQOS_i   ( timer.ar_qos    ),
+            .ARVALID_i ( timer.ar_valid  ),
+            .ARREADY_o ( timer.ar_ready  ),
+            .RID_o     ( timer.r_id      ),
+            .RDATA_o   ( timer.r_data    ),
+            .RRESP_o   ( timer.r_resp    ),
+            .RLAST_o   ( timer.r_last    ),
+            .RUSER_o   ( timer.r_user    ),
+            .RVALID_o  ( timer.r_valid   ),
+            .RREADY_i  ( timer.r_ready   ),
+            .PENABLE   ( timer_penable   ),
+            .PWRITE    ( timer_pwrite    ),
+            .PADDR     ( timer_paddr     ),
+            .PSEL      ( timer_psel      ),
+            .PWDATA    ( timer_pwdata    ),
+            .PRDATA    ( timer_prdata    ),
+            .PREADY    ( timer_pready    ),
+            .PSLVERR   ( timer_pslverr   )
+        );
+
+        apb_timer #(
+                .APB_ADDR_WIDTH ( 32 ),
+                .TIMER_CNT      ( 2  )
+        ) i_timer (
+            .HCLK    ( clk_i            ),
+            .HRESETn ( rst_ni           ),
+            .PSEL    ( timer_psel       ),
+            .PENABLE ( timer_penable    ),
+            .PWRITE  ( timer_pwrite     ),
+            .PADDR   ( timer_paddr      ),
+            .PWDATA  ( timer_pwdata     ),
+            .PRDATA  ( timer_prdata     ),
+            .PREADY  ( timer_pready     ),
+            .PSLVERR ( timer_pslverr    ),
+            .irq_o   ( irq_sources[6:3] )
+        );
+    end
 endmodule
diff --git a/tb/ariane_soc_pkg.sv b/tb/ariane_soc_pkg.sv
index 4e0ef3aa48212e48a474430e218c2310dc5d4593..8f522a2e1b9a38f28db4cc1322e0a36b6984d5a1 100644
--- a/tb/ariane_soc_pkg.sv
+++ b/tb/ariane_soc_pkg.sv
@@ -28,11 +28,12 @@ package ariane_soc;
     GPIO     = 1,
     Ethernet = 2,
     SPI      = 3,
-    UART     = 4,
-    PLIC     = 5,
-    CLINT    = 6,
-    ROM      = 7,
-    Debug    = 8
+    Timer    = 4,
+    UART     = 5,
+    PLIC     = 6,
+    CLINT    = 7,
+    ROM      = 8,
+    Debug    = 9
   } axi_slaves_t;
 
   localparam NB_PERIPHERALS = Debug + 1;
@@ -43,6 +44,7 @@ package ariane_soc;
   localparam logic[63:0] CLINTLength    = 64'hC0000;
   localparam logic[63:0] PLICLength     = 64'h3FF_FFFF;
   localparam logic[63:0] UARTLength     = 64'h1000;
+  localparam logic[63:0] TimerLength    = 64'h1000;
   localparam logic[63:0] SPILength      = 64'h800000;
   localparam logic[63:0] EthernetLength = 64'h10000;
   localparam logic[63:0] GPIOLength     = 64'h1000;
@@ -57,6 +59,7 @@ package ariane_soc;
     CLINTBase    = 64'h0200_0000,
     PLICBase     = 64'h0C00_0000,
     UARTBase     = 64'h1000_0000,
+    TimerBase    = 64'h1800_0000,
     SPIBase      = 64'h2000_0000,
     EthernetBase = 64'h3000_0000,
     GPIOBase     = 64'h4000_0000,
diff --git a/tb/ariane_testharness.sv b/tb/ariane_testharness.sv
index fec1e22a573da9df6cc5f98e009aaf7e85d2070b..075a305b9f3a836baceaf86e6be853306fa99ef8 100644
--- a/tb/ariane_testharness.sv
+++ b/tb/ariane_testharness.sv
@@ -551,6 +551,7 @@ module ariane_testharness #(
       ariane_soc::CLINTBase,
       ariane_soc::PLICBase,
       ariane_soc::UARTBase,
+      ariane_soc::TimerBase,
       ariane_soc::SPIBase,
       ariane_soc::EthernetBase,
       ariane_soc::GPIOBase,
@@ -562,6 +563,7 @@ module ariane_testharness #(
       ariane_soc::CLINTBase    + ariane_soc::CLINTLength - 1,
       ariane_soc::PLICBase     + ariane_soc::PLICLength - 1,
       ariane_soc::UARTBase     + ariane_soc::UARTLength - 1,
+      ariane_soc::TimerBase    + ariane_soc::TimerLength - 1,
       ariane_soc::SPIBase      + ariane_soc::SPILength - 1,
       ariane_soc::EthernetBase + ariane_soc::EthernetLength -1,
       ariane_soc::GPIOBase     + ariane_soc::GPIOLength - 1,
@@ -630,6 +632,7 @@ module ariane_testharness #(
     .uart      ( master[ariane_soc::UART]     ),
     .spi       ( master[ariane_soc::SPI]      ),
     .ethernet  ( master[ariane_soc::Ethernet] ),
+    .timer     ( master[ariane_soc::Timer]    ),
     .irq_o     ( irqs                         ),
     .rx_i      ( rx                           ),
     .tx_o      ( tx                           ),