|  | @@ -3,15 +3,16 @@
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // This is a DIO (2-bit, including command) SPI slave interface which
 | 
	
		
			
				|  |  |  // allows direct access to content in SDRAM. Additionally, each
 | 
	
		
			
				|  |  | -// direction has three interrupt flags (3-1); the FPGA CPU additionally
 | 
	
		
			
				|  |  | -// has a fourth interrupt condition (0) which indicates DRAM timing
 | 
	
		
			
				|  |  | -// overrun/underrun.
 | 
	
		
			
				|  |  | +// direction has 7 interrupt condition flags (7-1); the FPGA CPU
 | 
	
		
			
				|  |  | +// additionally has an internal interrupt condition (0) which
 | 
	
		
			
				|  |  | +// indicates DRAM timing overrun/underrun, also visible in the status
 | 
	
		
			
				|  |  | +// word as bit 0.
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // The SPI command byte is:
 | 
	
		
			
				|  |  | -// Bit [7:5]  - reserved, must be 0
 | 
	
		
			
				|  |  | -// Bit    4   - read/write#
 | 
	
		
			
				|  |  | -// Bit [3:2]  - clear upstream (FPGA->ESP) interrupt flag if nonzero
 | 
	
		
			
				|  |  | -// Bit [1:0]  - set downstream (ESP->FPGA) interrupt flag if nonzero
 | 
	
		
			
				|  |  | +// Bit    7   - save command timestamp
 | 
	
		
			
				|  |  | +// Bit    6   - read/write#
 | 
	
		
			
				|  |  | +// Bit [5:3]  - clear upstream (FPGA->ESP) interrupt flag if nonzero
 | 
	
		
			
				|  |  | +// Bit [2:0]  - set downstream (ESP->FPGA) interrupt flag if nonzero
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // CPU downstream interrupts are set after the transaction completes
 | 
	
		
			
				|  |  |  // (CS# goes high.)
 | 
	
	
		
			
				|  | @@ -20,19 +21,18 @@
 | 
	
		
			
				|  |  |  // contains dummy/status data:
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // Bit [31:16] = 16 LSB of 32 kHz RTC counter
 | 
	
		
			
				|  |  | -// Bit [15:12] = 4'b1001
 | 
	
		
			
				|  |  | -// Bit [11: 8] = 0 reserved
 | 
	
		
			
				|  |  | -// Bit [ 7: 5] = upstream interrupts pending
 | 
	
		
			
				|  |  | -// Bit      4  = downstream writes enabled
 | 
	
		
			
				|  |  | -// Bit [ 3: 1] = downstream interrupts pending
 | 
	
		
			
				|  |  | +// Bit [15: 9] = upstream interrupts pending
 | 
	
		
			
				|  |  | +// Bit      8  = downstream writes enabled
 | 
	
		
			
				|  |  | +// Bit [ 7: 1] = downstream interrupts pending
 | 
	
		
			
				|  |  |  // Bit      0  = underrun error
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // The following CPU registers are defined:
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  | -// 0	       = status bits [3:0] (downstream)
 | 
	
		
			
				|  |  | -// 1	       = write-1-clear of status bits [3:0]
 | 
	
		
			
				|  |  | -// 2           = status bits [7:4] (upstream)
 | 
	
		
			
				|  |  | -// 3           = write-1-set of status bits [7:4]
 | 
	
		
			
				|  |  | +// 0	       = status bits [7:0] (downstream)
 | 
	
		
			
				|  |  | +// 1	       = write-1-clear of status bits [7:0]
 | 
	
		
			
				|  |  | +// 2           = status bits [15:8] (upstream)
 | 
	
		
			
				|  |  | +// 3           = write-1-set of status bits [15:8]
 | 
	
		
			
				|  |  | +// 4           = timestamp (16 LSB of 32 kHz RTC counter) saved by cmd bit 7
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  module esp #(
 | 
	
		
			
				|  |  |  	     parameter        dram_bits = 25,
 | 
	
	
		
			
				|  | @@ -103,14 +103,15 @@ module esp #(
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     state_t    spi_state;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -   reg [ 4:0] spi_cmd;
 | 
	
		
			
				|  |  | +   reg [ 7:0] spi_cmd;
 | 
	
		
			
				|  |  |     reg [31:0] spi_shr;
 | 
	
		
			
				|  |  |     reg [ 3:0] spi_ctr;
 | 
	
		
			
				|  |  | -   reg [ 3:0] cpu_irq;
 | 
	
		
			
				|  |  | -   reg [ 3:0] cpu_set_irq;	// CPU IRQs to set once idle
 | 
	
		
			
				|  |  | +   reg [ 7:0] cpu_irq;
 | 
	
		
			
				|  |  | +   reg [ 7:0] cpu_set_irq;	// CPU IRQs to set once idle
 | 
	
		
			
				|  |  |     reg        cpu_send_irq;	// Ready to set CPU IRQs
 | 
	
		
			
				|  |  | -   reg [ 3:1] spi_irq;
 | 
	
		
			
				|  |  | -   reg [ 3:1] latched_spi_irq;	// SPI IRQ as of transition start
 | 
	
		
			
				|  |  | +   reg [ 7:1] spi_irq;
 | 
	
		
			
				|  |  | +   reg [ 7:1] latched_spi_irq;	// SPI IRQ as of transition start
 | 
	
		
			
				|  |  | +   reg [15:0] timestamp_q;
 | 
	
		
			
				|  |  |     reg [ 1:0] spi_out;
 | 
	
		
			
				|  |  |     reg	      spi_oe;
 | 
	
		
			
				|  |  |     reg [ 2:0] spi_wbe;		// Partial word write byte enables
 | 
	
	
		
			
				|  | @@ -120,7 +121,7 @@ module esp #(
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     assign spi_io = spi_oe ? spi_out : 2'bzz;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -   assign mem_write = ~spi_cmd[4];
 | 
	
		
			
				|  |  | +   assign mem_write = ~spi_cmd[6];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     wire [31:0] spi_indata = { spi_shr[29:0], spi_io_q };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -191,22 +192,14 @@ module esp #(
 | 
	
		
			
				|  |  |  		 4'b0000: begin
 | 
	
		
			
				|  |  |  		       // Load spi_shr, but account for endianness here...
 | 
	
		
			
				|  |  |  		       if (spi_state == st_io)
 | 
	
		
			
				|  |  | -			 begin
 | 
	
		
			
				|  |  | -			    // Memory output
 | 
	
		
			
				|  |  | -			    spi_shr[31:24]  <= mem_rdata[ 7: 0];
 | 
	
		
			
				|  |  | -			    spi_shr[23:16]  <= mem_rdata[15: 8];
 | 
	
		
			
				|  |  | -			    spi_shr[15: 8]  <= mem_rdata[23:16];
 | 
	
		
			
				|  |  | -			    spi_shr[ 7: 0]  <= mem_rdata[31:24];
 | 
	
		
			
				|  |  | -			 end
 | 
	
		
			
				|  |  | +			 spi_shr <= bswap32(mem_rdata);
 | 
	
		
			
				|  |  |  		       else
 | 
	
		
			
				|  |  | -			 begin
 | 
	
		
			
				|  |  | -			    // Status output
 | 
	
		
			
				|  |  | -			    spi_shr[31:28]  <= { latched_spi_irq, spi_wr_en };
 | 
	
		
			
				|  |  | -			    spi_shr[27:24]  <= cpu_irq;
 | 
	
		
			
				|  |  | -			    spi_shr[23:16]  <= 8'b1001_0000;
 | 
	
		
			
				|  |  | -			    spi_shr[15: 8]  <= rtc_ctr[ 7: 0];
 | 
	
		
			
				|  |  | -			    spi_shr[ 7: 0]  <= rtc_ctr[15: 8];
 | 
	
		
			
				|  |  | -			 end // else: !if(spi_state == st_io)
 | 
	
		
			
				|  |  | +			 // Status output
 | 
	
		
			
				|  |  | +			 spi_shr <= bswap32({
 | 
	
		
			
				|  |  | +					     rtc_ctr,
 | 
	
		
			
				|  |  | +					     latched_spi_irq, spi_wr_en,
 | 
	
		
			
				|  |  | +					     cpu_irq
 | 
	
		
			
				|  |  | +					     });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		       if (mem_valid && spi_state != st_cmd)
 | 
	
		
			
				|  |  |  			 begin
 | 
	
	
		
			
				|  | @@ -220,24 +213,26 @@ module esp #(
 | 
	
		
			
				|  |  |  			    // Do nothing
 | 
	
		
			
				|  |  |  			 end
 | 
	
		
			
				|  |  |  			 st_cmd: begin
 | 
	
		
			
				|  |  | -			    spi_cmd         <= spi_indata[5:0];
 | 
	
		
			
				|  |  | +			    spi_cmd         <= spi_indata[7:0];
 | 
	
		
			
				|  |  |  			    spi_state       <= st_addr;
 | 
	
		
			
				|  |  |  			    latched_spi_irq <= spi_irq;
 | 
	
		
			
				|  |  | -			    spi_mem_en      <= ~mem_write | spi_wr_en;
 | 
	
		
			
				|  |  | -			    for (int i = 1; i < 4; i++)
 | 
	
		
			
				|  |  | +			    for (int i = 1; i < 8; i++)
 | 
	
		
			
				|  |  |  			      begin
 | 
	
		
			
				|  |  | -				 if (spi_indata[3:2] == i)
 | 
	
		
			
				|  |  | +				 if (spi_indata[5:3] == i)
 | 
	
		
			
				|  |  |  				   spi_irq[i] <= 1'b0;
 | 
	
		
			
				|  |  | -				 if (spi_indata[1:0] == i)
 | 
	
		
			
				|  |  | +				 if (spi_indata[2:0] == i)
 | 
	
		
			
				|  |  |  				   cpu_set_irq[i] <= 1'b1;
 | 
	
		
			
				|  |  |  			      end
 | 
	
		
			
				|  |  | +			    if (spi_indata[7])
 | 
	
		
			
				|  |  | +			      timestamp_q <= rtc_ctr;
 | 
	
		
			
				|  |  |  			 end
 | 
	
		
			
				|  |  |  			 st_addr: begin
 | 
	
		
			
				|  |  | -			    mem_addr  <= spi_indata & mem_addr_mask;
 | 
	
		
			
				|  |  | -			    spi_state <= st_io;
 | 
	
		
			
				|  |  | -			    mem_valid <= ~mem_write;
 | 
	
		
			
				|  |  | -			    mem_wstrb <= 4'b0;
 | 
	
		
			
				|  |  | -			    spi_wbe   <= 3'b000;
 | 
	
		
			
				|  |  | +			    mem_addr   <= spi_indata & mem_addr_mask;
 | 
	
		
			
				|  |  | +			    spi_state  <= st_io;
 | 
	
		
			
				|  |  | +			    mem_valid  <= ~mem_write;
 | 
	
		
			
				|  |  | +			    spi_mem_en <= ~mem_write | spi_wr_en;
 | 
	
		
			
				|  |  | +			    mem_wstrb  <= 4'b0;
 | 
	
		
			
				|  |  | +			    spi_wbe    <= 3'b000;
 | 
	
		
			
				|  |  |  			    // If the first word is partial, skip ahead
 | 
	
		
			
				|  |  |  			    if (mem_write)
 | 
	
		
			
				|  |  |  			      spi_ctr[3:2] <= ~spi_indata[1:0];
 | 
	
	
		
			
				|  | @@ -287,34 +282,41 @@ module esp #(
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	  cpu_valid_q <= cpu_valid;
 | 
	
		
			
				|  |  |  	  if (cpu_valid & ~cpu_valid_q & cpu_wstrb[0])
 | 
	
		
			
				|  |  | -	    case (cpu_addr[1:0])
 | 
	
		
			
				|  |  | -	      2'b00:
 | 
	
		
			
				|  |  | -		 cpu_irq <= cpu_wdata[3:0];
 | 
	
		
			
				|  |  | -	      2'b01:
 | 
	
		
			
				|  |  | -		for (int i = 0; i < 4; i++)
 | 
	
		
			
				|  |  | +	    case (cpu_addr[2:0])
 | 
	
		
			
				|  |  | +	      3'b000:
 | 
	
		
			
				|  |  | +		 cpu_irq <= cpu_wdata[7:0];
 | 
	
		
			
				|  |  | +	      3'b001:
 | 
	
		
			
				|  |  | +		for (int i = 0; i < 8; i++)
 | 
	
		
			
				|  |  |  		  if (cpu_wdata[i])
 | 
	
		
			
				|  |  |  		    cpu_irq[i] <= cpu_send_irq & cpu_set_irq[i];
 | 
	
		
			
				|  |  | -	      2'b10:
 | 
	
		
			
				|  |  | -		 { spi_irq, spi_wr_en } <= cpu_wdata[3:0];
 | 
	
		
			
				|  |  | -	      2'b11: begin
 | 
	
		
			
				|  |  | +	      3'b010:
 | 
	
		
			
				|  |  | +		 { spi_irq, spi_wr_en } <= cpu_wdata[7:0];
 | 
	
		
			
				|  |  | +	      3'b011: begin
 | 
	
		
			
				|  |  |  		if (cpu_wdata[0])
 | 
	
		
			
				|  |  |  		  spi_wr_en <= 1'b1;
 | 
	
		
			
				|  |  | -		for (int i = 1; i < 4; i++)
 | 
	
		
			
				|  |  | +		for (int i = 1; i < 8; i++)
 | 
	
		
			
				|  |  |  		  if (cpu_wdata[i])
 | 
	
		
			
				|  |  |  		    spi_irq[i] <= 1'b1;
 | 
	
		
			
				|  |  |  	      end
 | 
	
		
			
				|  |  | -	    endcase // case (cpu_addr[1:0])
 | 
	
		
			
				|  |  | +	      default: begin
 | 
	
		
			
				|  |  | +		 // Do nothing
 | 
	
		
			
				|  |  | +	      end
 | 
	
		
			
				|  |  | +	    endcase // case (cpu_addr[2:0])
 | 
	
		
			
				|  |  |         end // else: !if(~rst_n)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     always @(posedge sys_clk)
 | 
	
		
			
				|  |  |       irq <= |cpu_irq;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |     always @(*)
 | 
	
		
			
				|  |  | -     casez (cpu_addr[1:0])
 | 
	
		
			
				|  |  | -       2'b0?:
 | 
	
		
			
				|  |  | +     casez (cpu_addr[2:0])
 | 
	
		
			
				|  |  | +       3'b000:
 | 
	
		
			
				|  |  |  	 cpu_rdata = { 28'b0, cpu_irq };
 | 
	
		
			
				|  |  | -       2'b1?:
 | 
	
		
			
				|  |  | +       3'b010:
 | 
	
		
			
				|  |  |  	 cpu_rdata = { 28'b0, spi_irq, spi_wr_en };
 | 
	
		
			
				|  |  | -     endcase // casez (cpu_addr[1:0])
 | 
	
		
			
				|  |  | +       3'b100:
 | 
	
		
			
				|  |  | +	 cpu_rdata = { 16'b0, timestamp_q };
 | 
	
		
			
				|  |  | +       default:
 | 
	
		
			
				|  |  | +	 cpu_rdata = 32'bx;
 | 
	
		
			
				|  |  | +     endcase // casez (cpu_addr[2:0])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  endmodule // esp
 |