Forráskód Böngészése

WIP: simplify the ABC-bus I/O interface

Do less offloading, to reduce complexity.
H. Peter Anvin 3 éve
szülő
commit
0924c443cd

+ 166 - 190
fpga/abcbus.sv

@@ -269,10 +269,7 @@ module abcbus (
    //
    // However, the rd and wr enable bits in the I/O map still apply.
    //
-   wire [7:0] abc_map_addr =
-	      abc_out_s[0] ? { 1'b1, iosel, 1'b0 } :
-	      abc_inp_s[0] ? { 1'b1, iosel, 1'b1 } :
-	      { 1'b0, abc_a_s[15:9] };
+   wire [7:0] abc_map_addr = { 1'b0, abc_a_s[15:9] };
    wire [35:0] rdata_abcmemmap;
    wire [35:0] abc_memmap_rd;
 
@@ -280,12 +277,7 @@ module abcbus (
    // For I/O, don't allow the read/write enables to conflict with
    // the direction of the I/O.
    //
-   wire [1:0] abcmap_masked_rdwr = cpu_wdata[31:30] &
-	      { ~cpu_addr[9] | ~cpu_addr[2],
-		~cpu_addr[9] |  cpu_addr[2] };
-
-   wire [8:0] next_dma_count = abc_dma_count - 1'b1;
-   wire       next_dma_empty = ~&next_dma_count;
+   wire [1:0]  abcmap_masked_rdwr = cpu_wdata[31:30];
 
    abcmapram abcmapram (
 			.aclr      ( ~rst_n ),
@@ -293,92 +285,30 @@ module abcbus (
 			.clock     ( sdram_clk ),
 
 			.address_a ( abc_map_addr ),
-			.data_a    ( { next_dma_count,
-				       abc_rden, abc_wren,
-				       abc_memaddr + 1'b1 } ),
-			.wren_a    ( abc_dma_update ),
-			.byteena_a ( 4'b1111 ),
+			.data_a    ( 36'bx ),
+			.wren_a    ( 1'b0 ),
+			.byteena_a ( 4'bxxxx ),
 			.q_a       ( abc_memmap_rd ),
 
 			.address_b ( cpu_addr[9:2] ),
-			.data_b    ( { cpu_wdata[8:0],
+			.data_b    ( { 9'bx,
 				       abcmap_masked_rdwr,
 				       cpu_wdata[24:0] } ),
-			.wren_b    ( map_valid & ~cpu_addr[11] & cpu_wstrb[0] ),
-			.byteena_b ( { cpu_addr[10],
-				       {3{~cpu_addr[10]}} } ),
+			.wren_b    ( map_valid & cpu_wstrb[0] ),
+			.byteena_b ( 4'b1111 ),
 
 			.q_b       ( rdata_abcmemmap )
 			);
 
-   // Note: added one extra cycle of pipelining here for timing
-   reg [24:0] abc_memaddr;
-   reg [8:0]  abc_dma_count;
-   reg	      abc_dma_nzero;
-   reg	      abc_rden;
-   reg	      abc_wren;
+   assign cpu_rdata_map =  { rdata_abcmemmap[26:25], 5'b0,
+			     rdata_abcmemmap[24:0] };
 
-   always @(negedge rst_n or posedge sdram_clk)
-     if (~rst_n)
-       begin
-	  abc_dma_count <= 9'b0;
-	  abc_dma_nzero <= 1'b0;
-	  abc_rden      <= 1'b0;
-	  abc_wren      <= 1'b0;
-	  abc_memaddr   <= 26'b0;
-       end
-     else
-       begin
-	  { abc_dma_count, abc_rden, abc_wren, abc_memaddr } <= abc_memmap_rd;
-	  abc_dma_nzero <= |abc_memmap_rd[35:27]; // -> |abc_dma_count
-       end
+   wire        abc_rden    = abc_memmap_rd[26];
+   wire        abc_wren    = abc_memmap_rd[25];
+   wire [24:0] abc_memaddr = abc_memmap_rd[24:0];
 
-   //
-   // RAM for the status register (INP 1). This is in a separate SRAM
-   // so that it can be adjusted for certain DMA events.
-   // bit [7:0] - status register value
-   // bit [8]   - clear bit 0 on read DMA empty
-   // bit [9]   - clear bit 0 on write DMA empty
-   // bit [10]  - clear bit 1 on write DMA empty
-   // bit [11]  - clear bit 7 on any DMA event
-   //
-   wire [15:0] status_out;
-   wire [15:0] rdata_status;
-
-   statusram statusram (
-			.aclr ( ~rst_n ),
-			.clock ( sdram_clk ),
-
-			.address_a ( iosel ),
-			.data_a    ( status_out &
-				     ~{ 4'hf0, status_out[11], 5'b00000,
-					status_out[10] & abc_out_s[0]
-					& next_dma_empty,
-					((status_out[9] & abc_out_s[0]) |
-					 (status_out[8] & abc_inp_s[0]))
-					& next_dma_empty } ),
-			.wren_a    ( abc_dma_update ),
-			.q_a       ( status_out ),
-
-			.address_b ( cpu_addr[7:2] ),
-			.data_b    ( cpu_wdata[11:0] ),
-			.q_b       ( rdata_status ),
-			.wren_b    ( map_valid & cpu_addr[11] & cpu_wstrb[0] )
-			);
-
-   assign cpu_rdata_map = cpu_addr[11] ?
-			  { 16'b0, rdata_status } :
-			  cpu_addr[10] ?
-			  { 23'b0, rdata_abcmemmap[35:27] } :
-			  { rdata_abcmemmap[26:25], 5'b0,
-			    rdata_abcmemmap[24:0] };
-
-   reg [24:4] abc_iobase;
    reg	      abc_memrd_en;
    reg	      abc_memwr_en;
-   reg	      abc_dma_en;
-   reg	      abc_iowr_en;
-   reg	      abc_iord_en;
    reg	      abc_do_memrd;
    reg	      abc_do_memwr;
    reg	      abc_racked;
@@ -393,16 +323,12 @@ module abcbus (
        begin
 	  abc_memrd_en   <= 1'b0;
 	  abc_memwr_en   <= 1'b0;
-	  abc_dma_en     <= 1'b0;
-	  abc_iord_en    <= 1'b0;
-	  abc_iowr_en    <= 1'b0;
 	  abc_do_memrd   <= 1'b0;
 	  abc_do_memwr   <= 1'b0;
 	  sdram_rrq      <= 1'b0;
 	  sdram_wrq      <= 1'b0;
 	  abc_racked     <= 1'b0;
 	  abc_wacked     <= 1'b0;
-	  abc_dma_update <= 1'b0;
        end
      else
        begin
@@ -411,152 +337,202 @@ module abcbus (
 	  // will have been stable for some time
 	  abc_memwr_en  <= abc_xmemwr;
 	  abc_memrd_en  <= abc_xmemrd;
-	  abc_dma_en    <= iosel_en & (abc_out[0] | abc_inp[0]) & abc_stb[3] &
-			   abc_dma_nzero;
-	  abc_iowr_en   <= iosel_en & |abc_out & abc_stb[3];
-	  abc_iord_en   <= iosel_en & |abc_inp & abc_stb[3];
-
-	  abc_do_memrd  <= abc_rden & (abc_memrd_en |
-				       (abc_iord_en & abc_inp[0]));
-	  abc_do_memwr  <= abc_wren & (abc_memwr_en | abc_iowr_en);
+
+	  abc_do_memrd  <= abc_rden & abc_memrd_en;
+	  abc_do_memwr  <= abc_wren & abc_memwr_en;
 	  abc_racked    <= abc_do_memrd & (sdram_rack | abc_racked);
 	  abc_wacked    <= abc_do_memwr & (sdram_wack | abc_wacked);
 
 	  sdram_rrq     <= abc_do_memrd & ~abc_racked;
 	  sdram_wrq     <= abc_do_memwr & ~abc_wacked;
-
-	  // This will be true for one cycle only, which is what we want
-	  abc_dma_update <= abc_dma_en &
-			    ((sdram_rrq & abc_racked) |
-			     (sdram_wrq & abc_wacked));
        end // else: !if(~rst_n)
 
-   assign sdram_addr =
-		      (abc_dma_en & |abc_dma_count) ? abc_memaddr :
-		      (abc_iord_en|abc_iowr_en) ? { abc_iobase, |abc_inp_s, abc_a_s[2:0] } :
-		      { abc_memaddr[24:9], abc_a_s[8:0] };
-
+   assign sdram_addr = { abc_memaddr[24:9], abc_a_s[8:0] };
    assign sdram_wd = abc_di;
+   
+   // I/O data registers; RST# is considered OUT 7 even through
+   // it is an IN from the ABC point of view.
+   //
+   // OUT register, written from ABC: <addr 2:0>   <data 7:0>
+   // IN register,  written from CPU: <enable 1:0> <status 7:0> <inp 7:0>
+   // Busy register: 
+   //
+   //   [7:0] - busy OUT status (write-1-clear)
+   //   [9:8] - busy IN status  (write-1-clear)
+   //    [15] - bus status change (write-1-clear)
+   //
+   // [23:16] - busy OUT mask
+   // [25:24] - busy IN mask
+   //    [31] - bus status change IRQ enable
+   //
+   // Assert WAIT# (deassert RDY) if the masked busy status is nonzero
+   // and an busy-unmasked I/O comes in.
+   //
+   // An IRQ is generated if the masked busy status is nonzero.
+   //
+   reg [9:0] busy_status;
+   reg [9:0] busy_mask;
+   reg [1:0] inp_en;
+   reg 	     bus_change_status;
+   reg 	     bus_change_mask;
+
+   wire [9:0] busy_io = { abc_inp[1:0], abc_rst, 1'b0,
+			  abc_out[4:1], abc_cs, abc_out[0] };
+
+   wire [9:0] set_busy = busy_io & busy_mask;
+   wire       is_busy = |(busy_status & busy_mask);
+
+   // WAIT# logic
+   reg 	      abc_wait_force = 1'b0; // Not cleared on internal reset!
+
+   always @(posedge sys_clk)
+     abc_wait <= abc_wait_force | (rst_n & |set_busy & is_busy);
 
-   // I/O status bits: sets the irq_status bits (sticky, write-1-clear)
-   // The RST# (INP 7) and CS# (OUT 1) signals are always valid
-   // regardless of the current select code; OUT 0/INP 0 only
-   // set the bit once the DMA counter reaches or already is zero.
-
-   wire [7:0] abc_inpflag = { abc_rst, 5'b00000,
-			      abc_iord_en & abc_rden & abc_inp[1],
-			      abc_iord_en & abc_rden & ~abc_dma_nzero & abc_inp[0] };
-   wire [7:0] abc_outflag = { 2'b00,
-			  {4{abc_iowr_en & abc_wren}} & abc_out[4:1],
-			  abc_cs,
-			  abc_iowr_en & abc_wren & ~abc_dma_nzero & abc_out[0] };
-
-   // DMA status register: set on *any* DMA access.
-   // bit 0 = out DMA; bit 1 = in DMA.
-   wire [1:0]  abc_dmaflag = { abc_iord_en & abc_rden & abc_dma_en,
-			       abc_iowr_en & abc_wren & abc_dma_en };
    //
-   // ABC-bus data bus handling
+   // I/O data registers
    //
-   always @(posedge sdram_clk or negedge rst_n)
+   reg [2:0]  reg_out_addr;
+   reg [7:0]  reg_out_data;
+   reg [7:0]  reg_inp_data[0:1];
+
+   // OUT logic
+   always @(posedge sdram_clk)
+     begin
+	if (|busy_io[7:0])
+	  begin
+	     reg_out_data <= abc_di;
+	     case (busy_io[7:0])
+	       8'b0000_0001: reg_out_addr <= 3'd0;
+	       8'b0000_0010: reg_out_addr <= 3'd1;
+	       8'b0000_0100: reg_out_addr <= 3'd2;
+	       8'b0000_1000: reg_out_addr <= 3'd3;
+	       8'b0001_0000: reg_out_addr <= 3'd4;
+	       8'b0010_0000: reg_out_addr <= 3'd5;
+	       8'b0100_0000: reg_out_addr <= 3'd6;
+	       8'b1000_0000: reg_out_addr <= 3'd7;
+	       default:      reg_out_addr <= 3'dx;
+	     endcase // case (busy_io)
+	  end // if (|busy_io[7:0])
+     end // always @ (posedge sdram_clk)
+
+   //
+   // ABC data out (= ABC host read) logic
+   //
+   always @(negedge rst_n or posedge sdram_clk)
      if (~rst_n)
        begin
-	  abc_do   <= 8'hxx;
 	  abc_d_oe <= 1'b0;
-       end
-     else if (abc_inp[1] & abc_iord_en & abc_rden)
-       begin
-	  abc_do   <= status_out;
-	  abc_d_oe <= 1'b1;
-       end
-     else if (abc_racked & sdram_rready)
-       begin
-	  abc_do   <= sdram_rd;
-	  abc_d_oe <= 1'b1;
+	  abc_do    <= 8'bx;
        end
      else
        begin
-	  abc_do   <= 8'hxx;
 	  abc_d_oe <= 1'b0;
-       end
+	  abc_do    <= 8'bx;
+	  
+	  if (abc_xmemrd & sdram_rready)
+	    begin
+	       abc_d_oe <= 1'b1;
+	       abc_do   <= sdram_rd;
+	    end
+	  else if (abc_inp[0] & inp_en[0])
+	    begin
+	       abc_d_oe <= 1'b1;
+	       abc_do   <= reg_inp_data[0];
+	    end
+	  else if (abc_inp[1] & inp_en[1])
+	    begin
+	       abc_d_oe <= 1'b1;
+	       abc_do   <= reg_inp_data[1];
+	    end
+       end // else: !if(~rst_n)
+   
+   // Bus status
+   reg  [31:0] abc_status[0:1];
+
+   always @(posedge sys_clk)
+     begin
+	abc_status[0] <= { 29'b0, abc800, abc_rst_s, abc_clk_active };
+	abc_status[1] <= abc_status[0];
+     end
 
+   wire bus_change = |(abc_status[0] ^ abc_status[1]);
+   
    //
-   // ABC-bus control/status registers
-   // All these registers are 32-bit access only except the I/O status
-   // register (which is write-1-clear.)
+   // Busy/IRQ status and CPU register writes
    //
-   reg	      clear_irq;
-   reg [31:0] irq_mask;
-
    always @(posedge sys_clk or negedge rst_n)
      if (~rst_n)
        begin
-	  abc_iobase <= 20'bx;
-	  irq_mask   <= 32'b0;
-	  clear_irq  <= 1'b0;
-	  // abc_resin, nmi, int and wait are deliberately not affected
+	  busy_status       <= 10'b0;
+	  busy_mask         <= 10'b0;
+	  inp_en            <= 2'b00;
+	  bus_change_status <= 1'b0;
+	  bus_change_mask   <= 1'b0;
+
+	  // abc_resin, nmi, int and force_wait are deliberately not affected
 	  // by an internal CPU reset. They are, however, initialized
 	  // to 0 on a CPU init (see above.)
        end
      else
        begin
-	  clear_irq <= 1'b0;
-
-	  if (abc_valid & cpu_wstrb[0])
+	  busy_status <= busy_status | set_busy;
+	  bus_change_status <= bus_change_status | bus_change;
+	  
+	  if (abc_valid)
 	    begin
-	       casez (cpu_addr[5:2])
-		 5'b??010:
-		   abc_iobase <= cpu_wdata[24:4];
-		 5'b??011:
-		   { abc_resin, abc_nmi, abc_int, abc_wait } <= cpu_wdata[3:0];
-		 5'b??100:
-		   irq_mask   <= cpu_wdata;
-		 5'b??101:
-		   clear_irq  <= 1'b1;
+	       casez (cpu_addr[5:2] )
+		 5'b??010: begin
+		   if (cpu_wstrb[0])
+		     busy_status[7:0] <= set_busy[7:0] | (busy_status[7:0] & ~cpu_wdata[7:0]);
+		    if (cpu_wstrb[1])
+		      begin
+			 busy_status[9:8] <= set_busy[9:8] | (busy_status[9:8] & ~cpu_wdata[9:8]);
+			 bus_change_status <= bus_change | (bus_change_status & ~cpu_wdata[15]);
+		      end
+		    if (cpu_wstrb[2])
+		      busy_mask[7:0] <= cpu_wdata[23:16] & ~8'h40;
+		    if (cpu_wstrb[3])
+		      begin
+			 busy_mask[9:8] <= cpu_wdata[25:24];
+			 bus_change_mask <= cpu_wdata[31];
+		      end
+		 end
+		 5'b???011: begin
+		    if (cpu_wstrb[0])
+		      begin
+			 abc_resin      <= cpu_wdata[3];
+			 abc_nmi        <= cpu_wdata[2];
+			 abc_int        <= cpu_wdata[1];
+			 abc_wait_force <= cpu_wdata[0];
+		      end
+		 end
+		 5'b???101: begin
+		    if (cpu_wstrb[0])
+		      reg_inp_data[0] <= cpu_wdata[7:0];
+		    if (cpu_wstrb[1])
+		      reg_inp_data[1] <= cpu_wdata[15:8];
+		    if (cpu_wstrb[2])
+		      inp_en <= cpu_wdata[17:16];
+		 end
 		 default:
 		   /* do nothing */ ;
 	       endcase // casez (cpu_addr[5:2])
 	    end // if (abc_valid & cpu_wstrb[0])
        end
 
-   reg  [2:0] abc_status[0:1];
-
-   always @(posedge sys_clk)
-     begin
-	abc_status[0]  <= { 5'b0, abc800, abc_rst_s, abc_clk_active };
-	abc_status[1]  <= abc_status[0];
-     end
-
-   wire [31:0] irq_status_in = { 5'b0, abc_status[1] ^ abc_status[0],
-				 6'b0, abc_dmaflag,
-				 abc_inpflag,
-				 abc_outflag };
-   reg  [31:0] irq_status;
-   wire [31:0] irq_status_mask = 32'h07_03_83_3f; // Valid status bits
-
-   always @(negedge rst_n or posedge sys_clk)
-     if (~rst_n)
-       irq_status <= 32'b0;
-     else
-       irq_status <= ( irq_status_in & irq_status_mask ) |
-		     (irq_status & ~({32{clear_irq}} & cpu_wdata));
-
    // Level triggered IRQ
-   always @(negedge rst_n or posedge sys_clk)
-     if (~rst_n)
-       irq <= 1'b0;
-     else
-       irq <= |(irq_status & irq_mask);
+   always @(posedge sys_clk)
+     irq <= is_busy | (bus_change_status & bus_change_mask);
 
    // Read MUX
    always_comb
      casez (cpu_addr[5:2])
-       5'b00000: cpu_rdata = { 24'b0, abc_status[0] };
+       5'b00000: cpu_rdata = abc_status[0];
        5'b00001: cpu_rdata = { 23'b0, ~iosel_en, ioselx[7:0] };
-       5'b00010: cpu_rdata = abc_iobase;
+       5'b00010: cpu_rdata = { 6'b0, busy_mask, 6'b0, busy_status };
        5'b00011: cpu_rdata = { 28'b0, abc_resin, abc_nmi, abc_int, abc_wait };
-       5'b00100: cpu_rdata = irq_mask & irq_status_mask;
-       5'b00101: cpu_rdata = irq_status;
+       5'b00100: cpu_rdata = { 21'b0, reg_out_addr, reg_out_data };
+       5'b00101: cpu_rdata = { 14'b0, inp_en, reg_inp_data[1], reg_inp_data[0] };
        default:  cpu_rdata = 32'bx;
      endcase // casez (cpu_addr[5:2])
 

BIN
fpga/output_files/max80.jbc


BIN
fpga/output_files/max80.jic


BIN
fpga/output_files/max80.pof


BIN
fpga/output_files/max80.sof


+ 4 - 4
fw/boot.mif

@@ -5542,10 +5542,10 @@ CONTENT BEGIN
 159F : 6F206465;
 15A0 : 4F203A6E;
 15A1 : 32207463;
-15A2 : 30322033;
-15A3 : 30203132;
-15A4 : 35343A30;
-15A5 : 0A30323A;
+15A2 : 30322035;
+15A3 : 31203132;
+15A4 : 35313A33;
+15A5 : 0A38313A;
 15A6 : 5452000A;
 15A7 : 49203A43;
 15A8 : 53204332;