TImer working with tests

TODO: think of other way of shifting in data. Bit errors make uploading difficult
This commit is contained in:
2026-02-25 22:01:28 +01:00
parent 3a3c951409
commit 838204653a
7 changed files with 142 additions and 16 deletions

View File

@@ -88,7 +88,7 @@ module mcu #(
) servile ( ) servile (
.i_clk(i_clk), .i_clk(i_clk),
.i_rst(rst), .i_rst(rst),
.i_timer_irq(1'b0), //timer_irq), .i_timer_irq(timer_irq),
//Memory interface //Memory interface
.o_wb_mem_adr(wb_mem_adr), .o_wb_mem_adr(wb_mem_adr),

View File

@@ -23,6 +23,26 @@ module top_generic #(
.clk_out_15(clk_15) .clk_out_15(clk_15)
); );
// Reset conditioning for button input:
// - asynchronous assert when button is pressed (aresetn=0)
// - synchronous, debounced deassert in clk_15 domain
localparam [17:0] RESET_RELEASE_CYCLES = sim ? 18'd16 : 18'd150000; // ~10 ms @ 15 MHz on hardware
reg [17:0] rst_cnt = 18'd0;
reg sys_reset_r = 1'b1;
always @(posedge clk_15 or negedge aresetn) begin
if (!aresetn) begin
rst_cnt <= 18'd0;
sys_reset_r <= 1'b1;
end else if (sys_reset_r) begin
if (rst_cnt == RESET_RELEASE_CYCLES - 1'b1)
sys_reset_r <= 1'b0;
else
rst_cnt <= rst_cnt + 1'b1;
end
end
wire sys_reset = sys_reset_r;
wire sys_resetn = !sys_reset_r;
wire [31:0] GPIO_A; wire [31:0] GPIO_A;
wire [31:0] GPIO_B; wire [31:0] GPIO_B;
wire [31:0] GPIO_C; wire [31:0] GPIO_C;
@@ -35,7 +55,7 @@ module top_generic #(
.sim(sim) .sim(sim)
) mcu ( ) mcu (
.i_clk(clk_15), .i_clk(clk_15),
.i_rst(!aresetn), .i_rst(sys_reset),
.i_GPI_A(GPIO_A), .i_GPI_A(GPIO_A),
.i_GPI_B(GPIO_B), .i_GPI_B(GPIO_B),
.i_GPI_C(GPIO_C), .i_GPI_C(GPIO_C),
@@ -55,7 +75,7 @@ module top_generic #(
.FS_HZ(80_000) .FS_HZ(80_000)
) nco ( ) nco (
.clk (clk_15), .clk (clk_15),
.rst_n (aresetn), .rst_n (sys_resetn),
.freq_hz(GPIO_A), .freq_hz(GPIO_A),
.sin_q15(sin_q15), .sin_q15(sin_q15),
.cos_q15(), .cos_q15(),

View File

@@ -107,7 +107,7 @@ module jtag_wb_bridge #(
reg [31:0] wb_dat_r; reg [31:0] wb_dat_r;
reg [3:0] wb_sel_r; reg [3:0] wb_sel_r;
reg wb_we_r; reg wb_we_r;
reg cmd_reset_pulse_r; reg cmd_reset_level_r;
reg [31:0] resp_addr_r; reg [31:0] resp_addr_r;
reg [7:0] resp_data_r; reg [7:0] resp_data_r;
@@ -133,7 +133,7 @@ module jtag_wb_bridge #(
assign o_wb_we = wb_we_r; assign o_wb_we = wb_we_r;
assign o_wb_cyc = wb_busy; assign o_wb_cyc = wb_busy;
assign o_wb_stb = wb_busy; assign o_wb_stb = wb_busy;
assign o_cmd_reset = cmd_reset_pulse_r; assign o_cmd_reset = cmd_reset_level_r;
always @(posedge i_clk) begin always @(posedge i_clk) begin
if (i_rst) begin if (i_rst) begin
@@ -148,7 +148,7 @@ module jtag_wb_bridge #(
wb_dat_r <= 32'b0; wb_dat_r <= 32'b0;
wb_sel_r <= 4'b0000; wb_sel_r <= 4'b0000;
wb_we_r <= 1'b0; wb_we_r <= 1'b0;
cmd_reset_pulse_r <= 1'b0; cmd_reset_level_r <= 1'b0;
resp_addr_r <= 32'b0; resp_addr_r <= 32'b0;
resp_data_r <= 8'b0; resp_data_r <= 8'b0;
end else begin end else begin
@@ -157,12 +157,11 @@ module jtag_wb_bridge #(
s_req_sync_3 <= s_req_sync_2; s_req_sync_3 <= s_req_sync_2;
s_cmd_sync_1 <= j_cmd_hold; s_cmd_sync_1 <= j_cmd_hold;
s_cmd_sync_2 <= s_cmd_sync_1; s_cmd_sync_2 <= s_cmd_sync_1;
cmd_reset_pulse_r <= 1'b0;
if (req_pulse && !wb_busy) begin if (req_pulse && !wb_busy) begin
wb_busy <= 1'b1; wb_busy <= 1'b1;
wb_we_r <= cmd_we; wb_we_r <= cmd_we;
wb_adr_r <= cmd_addr; wb_adr_r <= cmd_addr;
cmd_reset_level_r <= cmd_reset;
case (req_lane) case (req_lane)
2'b00: begin wb_sel_r <= 4'b0001; wb_dat_r <= {24'b0, cmd_wdata}; end 2'b00: begin wb_sel_r <= 4'b0001; wb_dat_r <= {24'b0, cmd_wdata}; end
@@ -170,8 +169,6 @@ module jtag_wb_bridge #(
2'b10: begin wb_sel_r <= 4'b0100; wb_dat_r <= {8'b0, cmd_wdata, 16'b0}; end 2'b10: begin wb_sel_r <= 4'b0100; wb_dat_r <= {8'b0, cmd_wdata, 16'b0}; end
default: begin wb_sel_r <= 4'b1000; wb_dat_r <= {cmd_wdata, 24'b0}; end default: begin wb_sel_r <= 4'b1000; wb_dat_r <= {cmd_wdata, 24'b0}; end
endcase endcase
cmd_reset_pulse_r <= cmd_reset;
end end
if (wb_busy && i_wb_ack) begin if (wb_busy && i_wb_ack) begin

View File

@@ -11,7 +11,7 @@ module tb_top_generic();
// 100 MHz board input clock // 100 MHz board input clock
initial aclk = 1'b0; initial aclk = 1'b0;
always #5 aclk = ~aclk; always #33.33 aclk = ~aclk;
// Hold reset low, then release // Hold reset low, then release
initial begin initial begin
@@ -39,7 +39,7 @@ module tb_top_generic();
$dumpvars(0, tb_top_generic); $dumpvars(0, tb_top_generic);
// Let firmware run for a while. // Let firmware run for a while.
#5_000_000; #2_000_000;
$finish; $finish;
end end
endmodule endmodule

View File

@@ -24,6 +24,8 @@ SECTIONS
{ {
__bss_start = .; __bss_start = .;
*(.bss .bss.*) *(.bss .bss.*)
*(.sbss .sbss.*)
*(.scommon)
*(COMMON) *(COMMON)
__bss_end = .; __bss_end = .;
} > RAM } > RAM

View File

@@ -1,7 +1,6 @@
.section .text.init .section .text.init
.globl _start .globl _start
.type _start, @function .type _start, @function
_start: _start:
la sp, __stack_top la sp, __stack_top
@@ -21,3 +20,80 @@ _start:
j 3b j 3b
.size _start, .-_start .size _start, .-_start
.section .text
.globl trap_entry
.type trap_entry, @function
trap_entry:
# Save full integer context (except x0/x2) because an interrupt can
# preempt code with live values in any register, not just caller-saved.
addi sp, sp, -128
sw ra, 124(sp)
sw gp, 120(sp)
sw tp, 116(sp)
sw t0, 112(sp)
sw t1, 108(sp)
sw t2, 104(sp)
sw s0, 100(sp)
sw s1, 96(sp)
sw a0, 92(sp)
sw a1, 88(sp)
sw a2, 84(sp)
sw a3, 80(sp)
sw a4, 76(sp)
sw a5, 72(sp)
sw a6, 68(sp)
sw a7, 64(sp)
sw s2, 60(sp)
sw s3, 56(sp)
sw s4, 52(sp)
sw s5, 48(sp)
sw s6, 44(sp)
sw s7, 40(sp)
sw s8, 36(sp)
sw s9, 32(sp)
sw s10, 28(sp)
sw s11, 24(sp)
sw t3, 20(sp)
sw t4, 16(sp)
sw t5, 12(sp)
sw t6, 8(sp)
csrr t0, mcause
li t1, 0x80000007 # machine timer interrupt (RV32)
bne t0, t1, 1f
call timer_isr # C function that ACKs/clears the timer so i_timer_irq goes low
1:
lw t6, 8(sp)
lw t5, 12(sp)
lw t4, 16(sp)
lw t3, 20(sp)
lw s11, 24(sp)
lw s10, 28(sp)
lw s9, 32(sp)
lw s8, 36(sp)
lw s7, 40(sp)
lw s6, 44(sp)
lw s5, 48(sp)
lw s4, 52(sp)
lw s3, 56(sp)
lw s2, 60(sp)
lw a7, 64(sp)
lw a6, 68(sp)
lw a5, 72(sp)
lw a4, 76(sp)
lw a3, 80(sp)
lw a2, 84(sp)
lw a1, 88(sp)
lw a0, 92(sp)
lw s1, 96(sp)
lw s0, 100(sp)
lw t2, 104(sp)
lw t1, 108(sp)
lw t0, 112(sp)
lw tp, 116(sp)
lw gp, 120(sp)
lw ra, 124(sp)
addi sp, sp, 128
mret

View File

@@ -1,14 +1,45 @@
#include <stdint.h> #include <stdint.h>
#define GPIO_BASE 0x40000000u #define GPIO_BASE 0x40000000u
static volatile uint32_t * const R_FREQ = (volatile uint32_t *)(GPIO_BASE+0);
static volatile uint32_t * const LEDS = (volatile uint32_t *)(GPIO_BASE+4);
static volatile uint32_t * const LEDGR = (volatile uint32_t *)(GPIO_BASE+8);
static volatile uint32_t * const R_FREQ = (volatile uint32_t *)GPIO_BASE; #define TIMER_BASE 0x40010000u
static volatile uint32_t * const TIMER = (volatile uint32_t *)(TIMER_BASE+0);
#define MSTATUS_MIE (1u << 3)
#define MIE_MTIE (1u << 7)
extern void trap_entry();
static inline void irq_init() {
/* mtvec first */
asm volatile ("csrw mtvec, %0" :: "r"(trap_entry));
/* enable machine timer interrupt */
asm volatile ("csrs mie, %0" :: "r"(MIE_MTIE));
/* global enable last */
asm volatile ("csrs mstatus, %0" :: "r"(MSTATUS_MIE));
}
void timer_isr(){
static int set = 0;
*TIMER = 18400;
*LEDGR = ~(*LEDGR);
}
void main(){ void main(){
irq_init();
*LEDGR = 3;
*TIMER = 18400;
for(;;){ for(;;){
for(int i=1000; i<10000; i++){ for(int i=1000; i<10000; i++){
*R_FREQ = i; *R_FREQ = i;
// for(int j=0; j<100; j++) asm volatile("nop"); for(int j=0; j<100; j++) asm volatile("nop");
} }
} }
} }