|  | @@ -383,23 +383,10 @@ module max80 (
 | 
	
		
			
				|  |  |     // cpu_mem_valid by address quadrant
 | 
	
		
			
				|  |  |     wire [ 3:0] cpu_mem_quad = cpu_mem_valid << cpu_mem_addr[31:30];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -   // Decode for small devices; use address space within range of
 | 
	
		
			
				|  |  | -   // negative offsets from the zero register [-1K,0)
 | 
	
		
			
				|  |  | -   //
 | 
	
		
			
				|  |  | -   // Device map:
 | 
	
		
			
				|  |  | -   //  0 - LED
 | 
	
		
			
				|  |  | -   //  1 - Reset
 | 
	
		
			
				|  |  | -   //  2 - SPI->SDRAM downloader
 | 
	
		
			
				|  |  | -   //  3 - Serial port
 | 
	
		
			
				|  |  | -   //  4 - SD card
 | 
	
		
			
				|  |  | -   //  5 - system local clock (not RTC)
 | 
	
		
			
				|  |  | -   //
 | 
	
		
			
				|  |  | -   // A device has IRQ (devno)+16 if it needs an interrupt.
 | 
	
		
			
				|  |  | -   //
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -   wire [15:0] iodev = cpu_mem_quad[3] << cpu_mem_addr[10:7];
 | 
	
		
			
				|  |  | -   tri0 [15:0] iodev_irq;	// tri0: if nothing is driving, value is 0
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +   // I/O device map from iodevs.conf
 | 
	
		
			
				|  |  | +   wire        iodev_mem_valid = cpu_mem_quad[3];
 | 
	
		
			
				|  |  | +`include "iodevs.vh"
 | 
	
		
			
				|  |  | +   
 | 
	
		
			
				|  |  |     //
 | 
	
		
			
				|  |  |     // SDRAM
 | 
	
		
			
				|  |  |     //
 | 
	
	
		
			
				|  | @@ -480,32 +467,31 @@ module max80 (
 | 
	
		
			
				|  |  |     // Embedded RISC-V CPU
 | 
	
		
			
				|  |  |     parameter cpu_fast_mem_bits = 13; /* 2^[this] * 4 bytes */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -   // Edge-triggered system IRQs not necessarily associated
 | 
	
		
			
				|  |  | -   // with a specific I/O device. picorv32 latches interrupts
 | 
	
		
			
				|  |  | +   // Edge-triggered IRQs. picorv32 latches interrupts
 | 
	
		
			
				|  |  |     // but doesn't edge detect for a slow signal, so do it
 | 
	
		
			
				|  |  |     // here instead and use level triggered signalling to the
 | 
	
		
			
				|  |  |     // CPU.
 | 
	
		
			
				|  |  |     wire [31:0] cpu_eoi;
 | 
	
		
			
				|  |  |     reg  [31:0] cpu_eoi_q;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -   tri0 [15:3] sys_irq;
 | 
	
		
			
				|  |  | -   reg  [15:3] sys_irq_q;
 | 
	
		
			
				|  |  | -   reg  [15:3] sys_irq_pending;
 | 
	
		
			
				|  |  | +   // sys_irq defined in iodevs.vh
 | 
	
		
			
				|  |  | +   reg  [31:0] sys_irq_q;
 | 
	
		
			
				|  |  | +   reg  [31:0] cpu_irq;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     always @(negedge rst_n or posedge sys_clk)
 | 
	
		
			
				|  |  |       if (~rst_n)
 | 
	
		
			
				|  |  |         begin
 | 
	
		
			
				|  |  | -	  sys_irq_q <= 1'b0;
 | 
	
		
			
				|  |  | -	  cpu_eoi_q <= 1'b0;
 | 
	
		
			
				|  |  | -	  sys_irq_pending <= 13'b0;
 | 
	
		
			
				|  |  | +	  sys_irq_q <= 32'b0;
 | 
	
		
			
				|  |  | +	  cpu_eoi_q <= 32'b0;
 | 
	
		
			
				|  |  | +	  cpu_irq   <= 32'b0;
 | 
	
		
			
				|  |  |         end
 | 
	
		
			
				|  |  |       else
 | 
	
		
			
				|  |  |         begin
 | 
	
		
			
				|  |  | -	  sys_irq_q <= sys_irq;
 | 
	
		
			
				|  |  | -	  cpu_eoi_q <= cpu_eoi;
 | 
	
		
			
				|  |  | +	  sys_irq_q <= sys_irq & irq_edge_mask;
 | 
	
		
			
				|  |  | +	  cpu_eoi_q <= cpu_eoi & irq_edge_mask;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	  sys_irq_pending <= (sys_irq & ~sys_irq_q)
 | 
	
		
			
				|  |  | -	    | (sys_irq_pending & ~(cpu_eoi[15:3] & ~cpu_eoi_q[15:3]));
 | 
	
		
			
				|  |  | +	  cpu_irq <= (sys_irq & ~sys_irq_q)
 | 
	
		
			
				|  |  | +	    | (cpu_irq & irq_edge_mask & ~(cpu_eoi & ~cpu_eoi_q));
 | 
	
		
			
				|  |  |         end
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     picorv32 #(
 | 
	
	
		
			
				|  | @@ -525,6 +511,7 @@ module max80 (
 | 
	
		
			
				|  |  |  	      .ENABLE_IRQ ( 1 ),
 | 
	
		
			
				|  |  |  	      .ENABLE_IRQ_QREGS ( 1 ),
 | 
	
		
			
				|  |  |  	      .ENABLE_IRQ_TIMER ( 1 ),
 | 
	
		
			
				|  |  | +	      .MASKED_IRQ ( irq_masked ),
 | 
	
		
			
				|  |  |  	      .LATCHED_IRQ ( 32'h0000_0007 ),
 | 
	
		
			
				|  |  |  	      .REGS_INIT_ZERO ( 1 ),
 | 
	
		
			
				|  |  |  	      .STACKADDR ( 32'h4 << cpu_fast_mem_bits )
 | 
	
	
		
			
				|  | @@ -552,7 +539,7 @@ module max80 (
 | 
	
		
			
				|  |  |  	.mem_la_addr  ( cpu_la_addr ),
 | 
	
		
			
				|  |  |  	.mem_la_wstrb ( cpu_la_wstrb ),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	.irq ( { iodev_irq, sys_irq_pending, 3'b000 } ),
 | 
	
		
			
				|  |  | +	.irq ( cpu_irq ),
 | 
	
		
			
				|  |  |  	.eoi ( cpu_eoi )
 | 
	
		
			
				|  |  |  	);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -577,7 +564,6 @@ module max80 (
 | 
	
		
			
				|  |  |     // Add a mandatory wait state to iodevs to reduce the size
 | 
	
		
			
				|  |  |     // of the CPU memory input MUX (it hurts timing on memory
 | 
	
		
			
				|  |  |     // accesses...)
 | 
	
		
			
				|  |  | -   tri1 [15:0] iodev_wait_n;
 | 
	
		
			
				|  |  |     reg	       iodev_mem_ready;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     always @(*)
 | 
	
	
		
			
				|  | @@ -609,20 +595,20 @@ module max80 (
 | 
	
		
			
				|  |  |  	    .rdata ( fast_mem_rdata )
 | 
	
		
			
				|  |  |  	    );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -   // Input data MUX
 | 
	
		
			
				|  |  | -   wire [31:0] iodev_rdata;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +   // Register I/O data to reduce the size of the read data MUX
 | 
	
		
			
				|  |  | +   reg [31:0]  iodev_rdata_q;
 | 
	
		
			
				|  |  | +   
 | 
	
		
			
				|  |  | +   // Read data MUX
 | 
	
		
			
				|  |  |     always @(*)
 | 
	
		
			
				|  |  |       case ( cpu_mem_quad )
 | 
	
		
			
				|  |  |         4'b0001: cpu_mem_rdata = fast_mem_rdata;
 | 
	
		
			
				|  |  |         4'b0010: cpu_mem_rdata = sdram_rdata;
 | 
	
		
			
				|  |  | -       4'b1000: cpu_mem_rdata = iodev_rdata;
 | 
	
		
			
				|  |  | +       4'b1000: cpu_mem_rdata = iodev_rdata_q;
 | 
	
		
			
				|  |  |         default: cpu_mem_rdata = 32'hxxxx_xxxx;
 | 
	
		
			
				|  |  |       endcase
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     // Hard system reset under program control
 | 
	
		
			
				|  |  | -   assign reset_cmd = rst_n & iodev[1] & cpu_mem_wstrb[0] & cpu_mem_wdata[0];
 | 
	
		
			
				|  |  | +   assign reset_cmd = iodev_valid_reset & cpu_mem_wstrb[0] & cpu_mem_wdata[0];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     // LED indication from the CPU
 | 
	
		
			
				|  |  |     reg [2:0]   led_q;
 | 
	
	
		
			
				|  | @@ -630,10 +616,11 @@ module max80 (
 | 
	
		
			
				|  |  |       if (~rst_n)
 | 
	
		
			
				|  |  |         led_q <= 3'b000;
 | 
	
		
			
				|  |  |       else
 | 
	
		
			
				|  |  | -       if ( iodev[0] & cpu_mem_wstrb[0] )
 | 
	
		
			
				|  |  | +       if ( iodev_valid_led & cpu_mem_wstrb[0] )
 | 
	
		
			
				|  |  |  	 led_q <= cpu_mem_wdata[2:0];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     assign led = led_q;
 | 
	
		
			
				|  |  | +   assign iodev_rdata_led = { 29'b0, led_q };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     //
 | 
	
		
			
				|  |  |     // Serial ROM (also configuration ROM.) Fast hardwired data download
 | 
	
	
		
			
				|  | @@ -661,6 +648,8 @@ module max80 (
 | 
	
		
			
				|  |  |     always @(posedge sys_clk)
 | 
	
		
			
				|  |  |       rom_done_q <= rom_done;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +   assign iodev_rdata_romcopy = { 31'b0, rom_done_q };
 | 
	
		
			
				|  |  | +   
 | 
	
		
			
				|  |  |     //
 | 
	
		
			
				|  |  |     // Serial port. Direct to the CP2102N for reworked
 | 
	
		
			
				|  |  |     // boards or to GPIO for non-reworked boards, depending on
 | 
	
	
		
			
				|  | @@ -677,19 +666,18 @@ module max80 (
 | 
	
		
			
				|  |  |     wire        tty_data_in;	// Input data
 | 
	
		
			
				|  |  |     wire        tty_cts_out;	// Assert CTS# externally
 | 
	
		
			
				|  |  |     wire        tty_rts_in;	// RTS# received from outside
 | 
	
		
			
				|  |  | -   wire [31:0] tty_rdata;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     assign tty_cts_out  = 1'b0;	// Assert CTS#
 | 
	
		
			
				|  |  | -   tty tty (
 | 
	
		
			
				|  |  | +   tty console (
 | 
	
		
			
				|  |  |  	    .rst_n ( rst_n ),
 | 
	
		
			
				|  |  | -	    .clk ( sys_clk ),
 | 
	
		
			
				|  |  | +	    .clk   ( sys_clk ),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	    .valid ( iodev[3] ),
 | 
	
		
			
				|  |  | +	    .valid ( iodev_valid_console ),
 | 
	
		
			
				|  |  |  	    .wstrb ( cpu_mem_wstrb ),
 | 
	
		
			
				|  |  |  	    .wdata ( cpu_mem_wdata ),
 | 
	
		
			
				|  |  | -	    .rdata ( tty_rdata ),
 | 
	
		
			
				|  |  | -	    .addr ( cpu_mem_addr[3:2] ),
 | 
	
		
			
				|  |  | -	    .irq  ( iodev_irq[3] ),
 | 
	
		
			
				|  |  | +	    .rdata ( iodev_rdata_console ),
 | 
	
		
			
				|  |  | +	    .addr  ( cpu_mem_addr[3:2] ),
 | 
	
		
			
				|  |  | +	    .irq   ( iodev_irq_console ),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	    .tty_txd ( tty_data_out ) // DTE -> DCE
 | 
	
		
			
				|  |  |  	    );
 | 
	
	
		
			
				|  | @@ -720,8 +708,6 @@ module max80 (
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     // SD card
 | 
	
		
			
				|  |  | -   wire [31:0] sdcard_rdata;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |     sdcard sdcard (
 | 
	
		
			
				|  |  |  		  .rst_n   ( rst_n ),
 | 
	
		
			
				|  |  |  		  .clk     ( sys_clk ),
 | 
	
	
		
			
				|  | @@ -732,18 +718,16 @@ module max80 (
 | 
	
		
			
				|  |  |  		  .sd_cd_n ( 1'b0 ),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		  .wdata   ( cpu_mem_wdata ),
 | 
	
		
			
				|  |  | -		  .rdata   ( sdcard_rdata ),
 | 
	
		
			
				|  |  | -		  .valid   ( iodev[4] ),
 | 
	
		
			
				|  |  | +		  .rdata   ( iodev_rdata_sdcard ),
 | 
	
		
			
				|  |  | +		  .valid   ( iodev_valid_sdcard ),
 | 
	
		
			
				|  |  |  		  .wstrb   ( cpu_mem_wstrb ),
 | 
	
		
			
				|  |  |  		  .addr    ( cpu_mem_addr[6:2] ),
 | 
	
		
			
				|  |  | -		  .wait_n  ( iodev_wait_n[4] )
 | 
	
		
			
				|  |  | +		  .wait_n  ( iodev_wait_n_sdcard )
 | 
	
		
			
				|  |  |  		  );
 | 
	
		
			
				|  |  |     assign sd_dat[2:1] = 2'bzz;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     // System local clock (not an RTC, but settable from one)
 | 
	
		
			
				|  |  |     // Also provides a periodic interrupt (set to 32 Hz)
 | 
	
		
			
				|  |  | -   wire [31:0] sysclock_rdata;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |     // XXX: the RTC 32 kHz signal is missing a pull-up,
 | 
	
		
			
				|  |  |     // so it will require board rework. For now, use an
 | 
	
		
			
				|  |  |     // divider down from the 84 MHz system clock. The
 | 
	
	
		
			
				|  | @@ -769,32 +753,24 @@ module max80 (
 | 
	
		
			
				|  |  |  		      .rtc_clk ( ctr_32khz ),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		      .wdata   ( cpu_mem_wdata ),
 | 
	
		
			
				|  |  | -		      .rdata   ( sysclock_rdata ),
 | 
	
		
			
				|  |  | -		      .valid   ( iodev[5] ),
 | 
	
		
			
				|  |  | +		      .rdata   ( iodev_rdata_sysclock ),
 | 
	
		
			
				|  |  | +		      .valid   ( iodev_valid_sysclock ),
 | 
	
		
			
				|  |  |  		      .wstrb   ( cpu_mem_wstrb ),
 | 
	
		
			
				|  |  |  		      .addr    ( cpu_mem_addr[2] ),
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		      .periodic ( sys_irq[3] )
 | 
	
		
			
				|  |  | +		      .periodic ( iodev_irq_sysclock )
 | 
	
		
			
				|  |  |  		      );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |     //
 | 
	
		
			
				|  |  | -   // I/O device input data (registered to reduce MUX overhead for
 | 
	
		
			
				|  |  | -   // the critical memory data paths.)
 | 
	
		
			
				|  |  | -   // abo
 | 
	
		
			
				|  |  | +   // Registering of I/O data and handling of iodev_mem_ready
 | 
	
		
			
				|  |  |     //
 | 
	
		
			
				|  |  |     always @(posedge sys_clk)
 | 
	
		
			
				|  |  | -     case ( cpu_mem_addr[10:7] )
 | 
	
		
			
				|  |  | -       4'd0:    iodev_rdata  <= { 29'b0, led_q };
 | 
	
		
			
				|  |  | -       4'd2:    iodev_rdata  <= { 31'b0, rom_done_q };
 | 
	
		
			
				|  |  | -       4'd3:	iodev_rdata  <= tty_rdata;
 | 
	
		
			
				|  |  | -       4'd4:    iodev_rdata  <= sdcard_rdata;
 | 
	
		
			
				|  |  | -       4'd5:    iodev_rdata  <= sysclock_rdata;
 | 
	
		
			
				|  |  | -       default: iodev_rdata  <= 32'h0;
 | 
	
		
			
				|  |  | -     endcase
 | 
	
		
			
				|  |  | +     iodev_rdata_q <= iodev_rdata;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     always @(negedge rst_n or posedge sys_clk)
 | 
	
		
			
				|  |  |       if (~rst_n)
 | 
	
		
			
				|  |  |         iodev_mem_ready <= 1'b0;
 | 
	
		
			
				|  |  |       else
 | 
	
		
			
				|  |  | -       iodev_mem_ready <= &iodev_wait_n & cpu_mem_valid;
 | 
	
		
			
				|  |  | +       iodev_mem_ready <= iodev_wait_n & cpu_mem_valid;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  endmodule
 |