diff --git a/rtl/core/mcu.v b/rtl/core/mcu.v index ca97279..0b91034 100644 --- a/rtl/core/mcu.v +++ b/rtl/core/mcu.v @@ -88,7 +88,7 @@ module mcu #( ) servile ( .i_clk(i_clk), .i_rst(rst), - .i_timer_irq(1'b0), //timer_irq), + .i_timer_irq(timer_irq), //Memory interface .o_wb_mem_adr(wb_mem_adr), diff --git a/rtl/toplevel/top_generic.v b/rtl/toplevel/top_generic.v index a2c3c6e..f79d30d 100644 --- a/rtl/toplevel/top_generic.v +++ b/rtl/toplevel/top_generic.v @@ -23,6 +23,26 @@ module top_generic #( .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_B; wire [31:0] GPIO_C; @@ -35,7 +55,7 @@ module top_generic #( .sim(sim) ) mcu ( .i_clk(clk_15), - .i_rst(!aresetn), + .i_rst(sys_reset), .i_GPI_A(GPIO_A), .i_GPI_B(GPIO_B), .i_GPI_C(GPIO_C), @@ -55,7 +75,7 @@ module top_generic #( .FS_HZ(80_000) ) nco ( .clk (clk_15), - .rst_n (aresetn), + .rst_n (sys_resetn), .freq_hz(GPIO_A), .sin_q15(sin_q15), .cos_q15(), diff --git a/rtl/wb/jtag_wb_bridge.v b/rtl/wb/jtag_wb_bridge.v index 1240379..f192eb0 100644 --- a/rtl/wb/jtag_wb_bridge.v +++ b/rtl/wb/jtag_wb_bridge.v @@ -107,7 +107,7 @@ module jtag_wb_bridge #( reg [31:0] wb_dat_r; reg [3:0] wb_sel_r; reg wb_we_r; - reg cmd_reset_pulse_r; + reg cmd_reset_level_r; reg [31:0] resp_addr_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_cyc = 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 if (i_rst) begin @@ -148,7 +148,7 @@ module jtag_wb_bridge #( wb_dat_r <= 32'b0; wb_sel_r <= 4'b0000; wb_we_r <= 1'b0; - cmd_reset_pulse_r <= 1'b0; + cmd_reset_level_r <= 1'b0; resp_addr_r <= 32'b0; resp_data_r <= 8'b0; end else begin @@ -157,12 +157,11 @@ module jtag_wb_bridge #( s_req_sync_3 <= s_req_sync_2; s_cmd_sync_1 <= j_cmd_hold; s_cmd_sync_2 <= s_cmd_sync_1; - cmd_reset_pulse_r <= 1'b0; - if (req_pulse && !wb_busy) begin wb_busy <= 1'b1; wb_we_r <= cmd_we; wb_adr_r <= cmd_addr; + cmd_reset_level_r <= cmd_reset; case (req_lane) 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 default: begin wb_sel_r <= 4'b1000; wb_dat_r <= {cmd_wdata, 24'b0}; end endcase - - cmd_reset_pulse_r <= cmd_reset; end if (wb_busy && i_wb_ack) begin diff --git a/sim/tb/tb_top_generic.v b/sim/tb/tb_top_generic.v index f7261ff..739caee 100644 --- a/sim/tb/tb_top_generic.v +++ b/sim/tb/tb_top_generic.v @@ -11,7 +11,7 @@ module tb_top_generic(); // 100 MHz board input clock initial aclk = 1'b0; - always #5 aclk = ~aclk; + always #33.33 aclk = ~aclk; // Hold reset low, then release initial begin @@ -39,7 +39,7 @@ module tb_top_generic(); $dumpvars(0, tb_top_generic); // Let firmware run for a while. - #5_000_000; + #2_000_000; $finish; end endmodule diff --git a/sw/sweep/link.ld b/sw/sweep/link.ld index 4f0c0db..3d2d455 100644 --- a/sw/sweep/link.ld +++ b/sw/sweep/link.ld @@ -24,6 +24,8 @@ SECTIONS { __bss_start = .; *(.bss .bss.*) + *(.sbss .sbss.*) + *(.scommon) *(COMMON) __bss_end = .; } > RAM diff --git a/sw/sweep/start.s b/sw/sweep/start.s index 837498e..2154050 100644 --- a/sw/sweep/start.s +++ b/sw/sweep/start.s @@ -1,7 +1,6 @@ .section .text.init .globl _start .type _start, @function - _start: la sp, __stack_top @@ -21,3 +20,80 @@ _start: j 3b .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 diff --git a/sw/sweep/sweep.c b/sw/sweep/sweep.c index 5d4e060..afd59eb 100644 --- a/sw/sweep/sweep.c +++ b/sw/sweep/sweep.c @@ -1,14 +1,45 @@ #include -#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(){ + irq_init(); + + *LEDGR = 3; + *TIMER = 18400; + for(;;){ for(int i=1000; i<10000; i++){ *R_FREQ = i; - // for(int j=0; j<100; j++) asm volatile("nop"); + for(int j=0; j<100; j++) asm volatile("nop"); } } } \ No newline at end of file