Browse Source

fpga/abcbus: only sample for 80/800 on clock changes; allow override

It Should Never[TM] happen, but Just In Case[TM], sample for
simultaneous XINPSTB# and XOUTPSTB# only on clock leading edges.

Add an ABC80/800 override control.
H. Peter Anvin 1 year ago
parent
commit
de6279a03d
2 changed files with 32 additions and 7 deletions
  1. 30 7
      fpga/abcbus.sv
  2. 2 0
      rv32/ioregs.h

+ 30 - 7
fpga/abcbus.sv

@@ -103,10 +103,7 @@ module abcbus (
 
    reg	     abc_clk_active;
 
-   // On ABC800, only one of XINPSTB# or XOUTPSTB# will be active;
-   // on ABC80 they will either be 00 or ZZ; in the latter case pulled
-   // low by external resistors.
-   wire      abc80  = abc_xinpstb_s & abc_xoutpstb_s;
+   reg	     abc80;
    wire      abc800 = ~abc80;
 
    wire	     xinpstb_s  = (abc800 & abc_xinpstb_s) | (|abc_inp_s);
@@ -188,9 +185,16 @@ module abcbus (
    assign abc_xm_x     = opt_mosfet(abc_xm, mosfet_installed[6]);
 
    // Detect ABC-bus clock: need a minimum frequency of 84/64 MHz
-   // to be considered live.
+   // to be considered live. Sample XINPSTB# and XOUTPSTB# on clock
+   // transitions to try to auto-detect ABC80 or ABC800.
+   //
+   // On ABC800, only one of XINPSTB# or XOUTPSTB# will be active;
+   // on ABC80 they will either be 00 or ZZ; in the latter case pulled
+   // low by external resistors.
    reg [2:0] abc_clk_ctr;
    reg [1:0] abc_clk_q;
+   reg	     abc80_force;
+   reg	     abc800_force;
 
    always @(negedge rst_n or posedge sys_clk)
      if (~rst_n)
@@ -205,7 +209,16 @@ module abcbus (
 	  case ( { abc_clk_q == 2'b10, stb_1mhz } )
 	    2'b10: begin
 	       if (abc_clk_ctr == 3'b111)
-		 abc_clk_active <= 1'b1;
+		 begin
+		    abc_clk_active <= 1'b1;
+
+		    if (abc80_force)
+		      abc80 <= 1'b1;
+		    else if (abc800_force)
+		      abc80 <= 1'b0;
+		    else
+		      abc80 <= abc_xinpstb_s & abc_xoutpstb_s;
+		 end
 	       else
 		 abc_clk_ctr <= abc_clk_ctr + 1'b1;
 	    end
@@ -574,6 +587,8 @@ module abcbus (
 	  bus_change_mask   <= 4'b0;
 	  abc800mac_en      <= 1'b0;
 	  romhack_en        <= 1'b0;
+	  abc80_force       <= 1'b0;
+	  abc800_force      <= 1'b0;
 
 	  // abc_resin, nmi, int and force_wait are deliberately not affected
 	  // by an internal CPU reset. They are, however, inherently asserted
@@ -588,6 +603,13 @@ module abcbus (
 	  if (abc_valid)
 	    begin
 	       casez (cpu_addr[6:2] )
+		 5'b00000: begin
+		    if (cpu_wstrb[1])
+		      begin
+			 abc80_force  <= cpu_wdata[8];
+			 abc800_force <= cpu_wdata[9];
+		      end
+		 end
 		 5'b00010: begin
 		   if (cpu_wstrb[0])
 		     busy_status[7:0] <= set_busy[7:0] | (busy_status[7:0] & ~cpu_wdata[7:0]);
@@ -648,7 +670,8 @@ module abcbus (
    // Read MUX
    always_comb
      casez (cpu_addr[6:2])
-       5'b00000: cpu_rdata = { 28'b0, abc_status[0] };
+       5'b00000: cpu_rdata = { 22'b0, abc800_force, abc80_force,
+			       4'b0, abc_status[0] };
        5'b00001: cpu_rdata = { 23'b0, ~iosel_en, ioselx[7:0] };
        5'b00010: cpu_rdata = { bus_change_mask, 2'b0, busy_mask,
 			       bus_change_status, 2'b0, busy_status };

+ 2 - 0
rv32/ioregs.h

@@ -107,6 +107,8 @@
 #define ABC_STATUS_LIVE		1
 #define ABC_STATUS_RST		2
 #define ABC_STATUS_800		4
+#define ABC_STATUS_FORCE_80	0x100
+#define ABC_STATUS_FORCE_800	0x200
 #define ABC_IOSEL		IODEVL(ABC,1)
 #define ABC_IOSEL_INVALID	0x100
 #define ABC_BUSY		IODEVL(ABC,2)