Переглянути джерело

Many timing fixes; better IRQ handling for abcbus

H. Peter Anvin 3 роки тому
батько
коміт
dd69eafb99

+ 131 - 85
fpga/abcbus.sv

@@ -108,16 +108,27 @@ module abcbus (
    wire      abc80  = abc_xinpstb_s & abc_xoutpstb_s;
    wire      abc800 = ~abc80;
 
-   // Memory read/write strobes
-   wire abc_xmemrd = abc_clk_active & abc_xmemfl_s;
-   wire abc_xmemwr = abc_clk_active &
+   // Memory and I/O read/write strobes for ABC-bus
+   reg	     abc_xmemrd;
+   reg       abc_xmemwr;
+   reg [1:0] abc_inp;
+   reg [4:0] abc_out;
+   reg	     abc_rst;
+   reg	     abc_cs;
+   reg [3:1] abc_stb;		// Delayed strobes
+
+   always @(posedge sdram_clk)
+     begin
+	abc_xmemrd <= abc_clk_active & abc_xmemfl_s;
+	abc_xmemwr <= abc_clk_active &
 	(abc800 ? abc_xmemw800_s : abc_xmemw80_s);
-
-   // I/O read/write strobes for ABC-bus only
-   wire [2:0] abc_inp = abc_inp_s & {3{abc_clk_active}} & {abc800, 2'b11};
-   wire [4:0] abc_out = abc_out_s & {5{abc_clk_active}};
-   wire       abc_rst = abc_rst_s & abc_clk_active;
-   wire       abc_cs  = abc_cs_s  & abc_clk_active;
+	abc_inp <= abc_inp_s & {2{abc_clk_active}};
+	abc_out <= abc_out_s & {5{abc_clk_active}};
+	abc_rst <= abc_rst_s & abc_clk_active;
+	abc_cs  <= abc_cs_s  & abc_clk_active;
+	abc_stb <= { abc_stb, |{abc_inp, abc_out, abc_rst,
+				abc_cs, abc_xmemrd, abc_xmemwr} };
+     end
 
    reg  [7:0] abc_do;
    assign abc_d    = abc_d_oe ? abc_do : 8'hzz;
@@ -258,16 +269,12 @@ module abcbus (
    //
    // However, the rd and wr enable bits in the I/O map still apply.
    //
-   wire [24:0] abc_memaddr;
-
    wire [7:0] abc_map_addr =
-	       abc_out_s[0] ? { 1'b1, iosel, 1'b0 } :
-	       abc_inp_s[0] ? { 1'b1, iosel, 1'b1 } :
+	      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 [8:0]  abc_dma_count;
    wire [35:0] rdata_abcmemmap;
-   wire        abc_rden;
-   wire        abc_wren;
+   wire [35:0] abc_memmap_rd;
 
    //
    // For I/O, don't allow the read/write enables to conflict with
@@ -288,8 +295,7 @@ module abcbus (
 				       abc_memaddr + 1'b1 } ),
 			.wren_a    ( abc_dma_update ),
 			.byteena_a ( 4'b1111 ),
-			.q_a       ( { abc_dma_count,
-				       abc_rden, abc_wren, abc_memaddr } ),
+			.q_a       ( abc_memmap_rd ),
 
 			.address_b ( cpu_addr[9:2] ),
 			.data_b    ( { cpu_wdata[8:0],
@@ -302,6 +308,28 @@ module abcbus (
 			.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;
+
+   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
+
    assign cpu_rdata_map = cpu_addr[10] ?
 			  { 23'b0, rdata_abcmemmap[35:27] } :
 			  { rdata_abcmemmap[26:25], 5'b0,
@@ -322,41 +350,33 @@ module abcbus (
    wire       abc_wack;
    wire       abc_rready;
 
-   // I/O status register: set on valid access, trigger IRQ.
-   // 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 zero, if applicable.
-   reg  [7:0] abc_inpflag;
-   wire [7:0] clear_inpflag;
-   reg  [7:0] abc_outflag;
-   wire [7:0] clear_outflag;
-
    always @(posedge sdram_clk or negedge rst_n)
      if (~rst_n)
        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_inpflag   <= 8'b0;
-	  abc_outflag   <= 8'b0;
+	  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
-	  // Careful with the registering here; need to make sure
-	  // abcmapram is caught up
+	  // Careful with the registering here: need to make sure
+	  // abcmapram is caught up for I/O; for memory the address
+	  // 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_iowr_en   <= iosel_en & |abc_out;
-	  abc_iord_en   <= iosel_en & |abc_inp;
+	  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_do_memwr  <= abc_wren & (abc_memwr_en | abc_iowr_en);
@@ -370,19 +390,9 @@ module abcbus (
 	  abc_dma_update <= abc_dma_en &
 			    ((sdram_rrq & abc_racked) |
 			     (sdram_wrq & abc_wacked));
-
-	  abc_inpflag <= ~clear_inpflag &
-			 (abc_inpflag |
-			  { abc_rst, 4'b0000,
-			    {2{abc_iord_en}} & abc_inp[2:1],
-			    abc_iord_en & ~|abc_dma_count & abc_inp[0] });
-	  abc_outflag <= ~clear_outflag &
-			 (abc_outflag |
-			  { 2'b00, {4{abc_iowr_en}} & abc_out[4:1],
-			    abc_cs,
-			    abc_iowr_en & ~|abc_dma_count & abc_out[0] });
        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] } :
@@ -390,6 +400,23 @@ module abcbus (
 
    assign sdram_wd = abc_di;
 
+   // 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_inp[1],
+			      abc_iord_en & ~abc_dma_nzero & abc_inp[0] };
+   wire [7:0] abc_outflag = { 2'b00,
+			  {4{abc_iowr_en}} & abc_out[4:1],
+			  abc_cs,
+			  abc_iowr_en & ~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_dma_en,
+			       abc_iowr_en & abc_dma_en };
    //
    // ABC-bus data bus handling
    //
@@ -415,54 +442,73 @@ module abcbus (
    // All these registers are 32-bit access only except the I/O status
    // register (which is write-1-clear.)
    //
-   assign clear_inpflag = {8{abc_valid & cpu_addr[5:2] == 5'b00011
-			     & cpu_wstrb[1]}} & cpu_wdata[15:8];
-   assign clear_outflag = {8{abc_valid & cpu_addr[5:2] == 5'b00011
-			     & cpu_wstrb[0]}} & cpu_wdata[7:0];
+   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;
        end
-     else if (abc_valid & cpu_wstrb[0])
+     else
        begin
-	  casez (cpu_addr[5:2])
-	    5'b???10:
-	      abc_iobase <= cpu_wdata[24:4];
-	    default:
-	      /* do nothing */ ;
-	  endcase
+	  clear_irq <= 1'b0;
+
+	  if (abc_valid & cpu_wstrb[0])
+	    begin
+	       casez (cpu_addr[5:2])
+		 5'b??010:
+		   abc_iobase <= cpu_wdata[24:4];
+		 5'b??100:
+		   irq_mask   <= cpu_wdata;
+		 5'b??100:
+		   clear_irq  <= 1'b1;
+		 default:
+		   /* do nothing */ ;
+	       endcase // casez (cpu_addr[5:2])
+	    end // if (abc_valid & cpu_wstrb[0])
        end
 
-   reg [31:0] abc_status[0:1];
+   reg  [2: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];
+	abc_status[0]  <= { 5'b0, abc800, abc_rst_s, abc_clk_active };
+	abc_status[1]  <= abc_status[0];
      end
 
-   wire [15:0] abc_iostatus = { abc_inpflag, abc_outflag };
-   reg [15:0]  abc_iostatus_q;
-   always @(posedge sys_clk)
-     abc_iostatus_q <= abc_iostatus;
+   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);
 
+   // Read MUX
    always_comb
      casez (cpu_addr[5:2])
-       5'b00000: cpu_rdata = abc_status[0];
+       5'b00000: cpu_rdata = { 24'b0, abc_status[0] };
        5'b00001: cpu_rdata = ioselx[7:0];
        5'b00010: cpu_rdata = abc_iobase;
-       5'b00011: cpu_rdata = { 16'b0, abc_iostatus };
+       5'b00100: cpu_rdata = irq_mask & irq_status_mask;
+       5'b00101: cpu_rdata = irq_status;
        default:  cpu_rdata = 32'bx;
      endcase // casez (cpu_addr[5:2])
 
-   // irq is edge-triggered on either changes to abc_status
-   // or bits set in iostatus.
-   always @(negedge rst_n or posedge sys_clk)
-     if (~rst_n)
-       irq <= 1'b0;
-     else
-       irq <= (abc_status[1] != abc_status[0]) |
-	      (|(abc_iostatus & ~abc_iostatus_q));
-
 endmodule // abcbus

+ 1 - 1
fpga/fast_mem.sv

@@ -21,7 +21,7 @@ module fast_mem
 		  .byteena ( wstrb ),
 		  .clock ( clk ),
 		  .data ( wdata ),
-		  .rden ( read ),
+		  .rden ( 1'b1 ), // Slows down too much to modulate
 		  .wren ( write ),
 		  .q ( rdata )
 		  );

+ 1 - 1
fpga/iodevs.vh

@@ -74,7 +74,7 @@
 	assign sys_irq[ 8] = iodev_irq_esp[0];
 	assign sys_irq[ 9] = iodev_irq_abc[0];
 
-	localparam [31:0] irq_edge_mask =  32'h00000288;
+	localparam [31:0] irq_edge_mask =  32'h00000088;
 	localparam [31:0] irq_masked    = ~32'h000003ff;
 
 	wire iodev_wait_n = (&iodev_wait_n_sys) & 

+ 55 - 16
fpga/max80.sdc

@@ -16,29 +16,29 @@ set_clock_groups -asynchronous -group {ctr_32khz}
 # Automatically calculate clock uncertainty to jitter and other effects.
 derive_clock_uncertainty
 
+# Don't report signaltap clock problems...
+set_false_path -to [get_registers sld_signaltap:*]
+
+# -------- PLL clock mappings --------
+
+set sdram_out_clk [get_clocks {pll|*|clk[0]}]
+set sdram_clk     [get_clocks {pll|*|clk[4]}]
+set sys_clk       [get_clocks {pll|*|clk[1]}]
+set vid_clk       [get_clocks {pll|*|clk[2]}]
+set flash_clk     [get_clocks {pll|*|clk[3]}]
+
+set main_clocks   [get_clocks {pll|*}]
+
 # Reset isn't actually a clock, but Quartus thinks it is
 create_generated_clock -name rst_n \
-    -source [get_nets pll|*clk\[1\]] \
+    -source [get_nets {pll|*|*clk[1]}] \
     [get_registers rst_n]
 
 # Reset is asynchronous  with everything as far as we are concerned.
-set main_clocks [get_clocks pll|*]
 set_clock_groups -asynchronous \
     -group $main_clocks \
     -group [get_clocks rst_n]
 
-set sdram_out_clk [get_clocks pll|*|clk\[0\]]
-set sdram_clk     [get_clocks pll|*|clk\[4\]]
-set cpu_clk       [get_clocks pll|*|clk\[1\]]
-set vid_clk       [get_clocks pll|*|clk\[2\]]
-set flash_clk     [get_clocks pll|*|clk\[3\]]
-
-# SDRAM I/O constraints
-set sr_data_out [remove_from_collection [get_ports sr_*] sr_clk]
-set sr_data_in  [get_ports sr_dq\[*\]]
-set_max_skew -to $sr_data_out 0.100ns
-set_input_delay  -clock $sdram_clk 0.500ns  $sr_data_in
-
 # Anything that feeds into a synchronizer is by definition
 # asynchronous, but encode it as allowing multicycle of one
 # clock, to limit the possible skew (but it is of course not possible
@@ -48,10 +48,49 @@ set_multicycle_path -from [all_clocks] -to $synchro_inputs \
     -start -setup 2
 set_multicycle_path -from [all_clocks] -to $synchro_inputs \
     -start -hold 1
+
+
+# -------- SDRAM I/O constraints --------
+
+set sr_data_out [remove_from_collection [get_ports sr_*] sr_clk]
+set sr_data_in  [get_ports sr_dq\[*\]]
+set_max_skew -to $sr_data_out 0.100ns
+set_input_delay  -clock $sdram_clk 0.500ns  $sr_data_in
+
 set_multicycle_path -from $sdram_clk -to $sdram_out_clk \
     -start -setup 2
 set_multicycle_path -from $sdram_clk -to $sdram_out_clk \
     -start -hold 0
 
-# Don't report signaltap clock problems...
-set_false_path -to [get_registers sld_signaltap:*]
+# -------- SPI ROM multicycle paths --------
+
+# the load of the spi_data_ctr register happens no less than 2 target
+# clocks after datalen is loaded by the CPU
+set_multicycle_path -from [get_registers {spirom:*|datalen[*]}] \
+    -to [get_registers {spirom:*|spi_data_ctr[*]}] -end -setup 2
+set_multicycle_path -from [get_registers {spirom:*|datalen[*]}] \
+    -to [get_registers {spirom:*|spi_data_ctr[*]}] -end -hold 1
+
+# A load of romstart does not affect spi_cmd for a minimum of 3 target
+# clock cycles (in reality much more, since the CPU needs to
+# write datalen in order to start the transfer)
+set_multicycle_path -from [get_registers {spirom:*|romstart[*]}] \
+    -to [get_registers {spirom:*|spi_cmd[*]}] -end -setup 3
+set_multicycle_path -from [get_registers {spirom:*|romstart[*]}] \
+    -to [get_registers {spirom:*|spi_cmd[*]}] -end -hold 2
+
+# CS# going low to spi_clk_en is a minimum of one clock cycle, which allows
+# an extra clock cycle before spi_cmd needs to stop resetting
+set_multicycle_path -from [get_registers {spirom:*|spi_cs_n}] \
+    -to [get_registers {spirom:*|spi_cmd[*]}] -end -setup 2
+set_multicycle_path -from [get_registers {spirom:*|spi_cs_n}] \
+    -to [get_registers {spirom:*|spi_cmd[*]}] -end -hold 1
+
+# -------- CPU/fastmem multicycle paths --------
+
+# We never read and write in the same clock cycle, thus there is a multicycle
+# path from the write enable register to anything in the CPU itself
+set_multicycle_path -from [get_keepers {fast_mem:fast_mem|*porta_we_reg*}] \
+    -to [get_keepers {picorv32:cpu|*}] -start -setup 2
+set_multicycle_path -from [get_keepers {fast_mem:fast_mem|*porta_we_reg*}] \
+    -to [get_keepers {picorv32:cpu|*}] -start -hold 1

BIN
fpga/output_files/max80.jbc


BIN
fpga/output_files/max80.jic


BIN
fpga/output_files/max80.pof


BIN
fpga/output_files/max80.sof


+ 25 - 12
fpga/spirom.sv

@@ -192,10 +192,19 @@ module spirom (
 
    reg [5:0]   spi_cmd_ctr;
    reg [23:-2] spi_data_ctr;
-   reg	       spi_clk_en    = 1'b0;
-   reg	       spi_mosi_en = 1'b1;
+   reg	       spi_clk_en = 1'b0;
+   reg	       spi_mosi_en;
    reg [1:0]   go_spi_q;
-   reg	       load_cmd;
+   wire        go_spi_s;
+
+   // Explicit synchronizer for go_spi
+   synchronizer #(.width(1)) go_spi_synchro
+     (
+      .rst_n ( rst_n ),
+      .clk ( rom_clk ),
+      .d ( go_spi ),
+      .q ( go_spi_s )
+      );
 
    ddio_out spi_clk_buf (
 			 .aclr ( ~rst_n ),
@@ -214,26 +223,30 @@ module spirom (
 	  spi_cs_n     <= 1'b1;
 	  spi_in_req   <= 1'b0;
 	  spi_in_req_q <= 1'b0;
-	  go_spi_q     <= 2'b00;
+	  spi_mosi_en  <= 1'b1;
+	  go_spi_q     <= 4'b0000;
        end
      else
        begin
-	  go_spi_q     <= { go_spi_q[0], go_spi };
+	  go_spi_q     <= { go_spi_q[0], go_spi_s };
 	  spi_in_q     <= spi_io;
 	  spi_in_req   <= 1'b0;
 	  spi_in_req_q <= spi_in_req;
 	  spi_clk_en   <= 1'b0;
+	  spi_cs_n     <= 1'b1;
 
+	  // Note: datalen <- spi_data_ctr is a 2-cycle multipath
 	  if (go_spi_q == 2'b01)
 	    begin
 	       spi_data_ctr <= { datalen, 5'b0 };
 	       spi_cmd_ctr  <= 6'b0;
+	       spi_cs_n     <= 1'b0;
 	    end
 
-	  if ( ~|spi_data_ctr )
+	  if ( ~|spi_data_ctr | ~go_spi_q[1] )
 	    begin
-	       spi_cs_n   <= 1'b1;
-	       spi_clk_en <= 1'b0;
+	       spi_clk_en  <= 1'b0;
+	       spi_mosi_en <= 1'b1;
 	    end
 	  else
 	    begin
@@ -244,6 +257,9 @@ module spirom (
 		    spi_clk_en <= (~wrusedw) >= 12'd128;
 		    if ( spi_clk_en )
 		      begin
+			 if ( spi_cmd_ctr[5] & spi_cmd_ctr[2] )
+			   spi_mosi_en <= 1'b0;
+
 			 if ( spi_cmd_ctr[5] & spi_cmd_ctr[3] )
 			   begin
 			      spi_in_req <= 1'b1;
@@ -269,12 +285,11 @@ module spirom (
      if (~rst_n)
        begin
 	  spi_cmd      <= 32'bx;	// Fast Read Dual Output
-	  spi_mosi_en  <= 1'b1;
 	  spi_clk_en_q <= 1'b0;
        end
      else
        begin
-	  if (!spi_cmd_ctr)
+	  if (spi_cs_n)
 	    begin
 	       spi_cmd[31:24] <= 8'h3b;	// Fast Read Dual Output
 	       spi_cmd[23: 0] <= { romstart, 3'b000 }; // Byte address
@@ -283,8 +298,6 @@ module spirom (
 	  spi_clk_en_q <= spi_clk_en;
 	  if ( spi_clk_en_q )
 	    spi_cmd <= (spi_cmd << 1) | 1'b1;
-
-	  spi_mosi_en <= spi_cs_n | (spi_cmd_ctr < 6'd36);
        end
 
 endmodule // spirom

+ 4 - 4
fw/boot.mif

@@ -5283,11 +5283,11 @@ CONTENT BEGIN
 149C : 656C6970;
 149D : 6E6F2064;
 149E : 634F203A;
-149F : 39312074;
+149F : 31322074;
 14A0 : 32303220;
-14A1 : 37312031;
-14A2 : 3A34353A;
-14A3 : 0A0A3234;
+14A1 : 39302031;
+14A2 : 3A36303A;
+14A3 : 0A0A3430;
 14A4 : 63647300;
 14A5 : 5F647261;
 14A6 : 64616572;

+ 6 - 3
fw/ioregs.h

@@ -106,9 +106,12 @@
 #define ABC_STATUS_800		4
 #define ABC_IOSEL		IODEVL(ABC,1)
 #define ABC_IOBASE		IODEVL(ABC,2)
-#define ABC_IOSTATUS		IODEVL(ABC,3)
-#define ABC_OUTSTATUS		IODEVB0(ABC,3)
-#define ABC_INPSTATUS		IODEVB1(ABC,3)
+#define ABC_IRQMASK		IODEVL(ABC,4)
+#define ABC_IRQSTATUS		IODEVL(ABC,5)
+#define ABC_OUTSTATUS		IODEVB0(ABC,5)
+#define ABC_INPSTATUS		IODEVB1(ABC,5)
+#define ABC_DMASTATUS		IODEVB2(ABC,5)
+#define ABC_CHGSTATUS		IODEVB3(ABC,5)
 
 #define ABCMEMMAP_PAGE(n)	IODEVL(ABCMEMMAP,n)
 #define ABCMEMMAP_WRPORT(n)	IODEVL(ABCMEMMAP,128+((n) << 1))

+ 1 - 1
iodevs.conf

@@ -21,6 +21,6 @@ our @iodevs = (
     { -name => 'sdcard',    -irq => 'l' },
     { -name => 'i2c',       -irq => 'e' },
     { -name => 'esp',       -irq => 'l' },
-    { -name => 'abc',       -irq => 'e' },
+    { -name => 'abc',       -irq => 'l' },
     { -name => 'abcmemmap', -xdev => 1 },
 );