hoglet67 / PiTubeDirect

Bare-metal Raspberry Pi project that attaches to the Acorn TUBE interface and emulates many BBC Micro Co Processors
GNU General Public License v3.0
187 stars 23 forks source link

Two byte data transfer flags incorrect #179

Closed hoglet67 closed 1 year ago

hoglet67 commented 1 year ago

After fixing #178 and doing more testing, it looks like there is an issue with the parasite flags in two-byte mode.

This is used by ANFS type=2 transfers (parasite-to-host, i.e. *SAVE)

I believe it only affects the RISC-V Co Processor, because all the other Co Processor use pace the transfer using the NMI interrupt (which I think is correct), where as the RISC-V Co Processor is unique in that it polls the flags in R3 status:

Type2:
    lb      t0, R4STATUS(gp)            # Test for an pending interrupt signalling end of transfer
    bltz    t0, Release
    lb      t0, R3STATUS(gp)
    andi    t0, t0, 0x40
    beqz    t0, Type2
    lh      t0, (t2)                    # load half word from memory
    sb      t0, R3DATA(gp)              # store lo byte to tube
    srli    t0, t0, 8
    sb      t0, R3DATA(gp)              # store hi byte to tube
    addi    t2, t2, 2
    j       Type2

App Note 004 says the following:

Register 3 Operation Register 3 is intended to enable high speed transfers of large blocks of data across the tube. It can operate in one or two byte mode, depending on the V flag. In one byte mode the status bits make each FIFO appear to be a single byte latch - after one byte is written the register appears to be full. In two byte mode the data available flag will only be asserted when two bytes have been entered, and the not full flag will only be asserted when both bytes have been removed. Thus data available going active means that two bytes are available, but it will remain active until both bytes have been removed. Not full going active means that the register is empty, but it will remain active until both bytes have been entered. PNMI, N and DRQ also remain active until the full two byte operation is completed.

In both one-byte and two byte-mode, the behaviour should be the same: the not full flag (bit 6) should only be asserted when the FIFO is empty.

That's not what the current tube_host_read() code does:

   case 5: /*Register 3*/
      if (ph3pos > 0)
      {
         PH3_0 = BYTE_TO_WORD(PH3_1);
         ph3pos--;
         PSTAT3 |= 0xC0;
         if (!ph3pos) HSTAT3 &= (uint32_t)~HBIT_7;
         if ((HSTAT1 & HBIT_3) && (ph3pos == 0)) tube_irq|=NMI_BIT;
         //tube_updateints_NMI();
      }
      break;

Currently not full flag is asserted when host reads the first of the two bytes. The Co Processer then quickly deposits two more bytes, the second of these overflowing the FIFO and being dropped.

I think the code should be changed to:

   case 5: /*Register 3*/
      if (ph3pos > 0)
      {
         PH3_0 = BYTE_TO_WORD(PH3_1);
         ph3pos--;
         if (!ph3pos) {                             // Test if PH3 empty
            HSTAT3 &= (uint32_t)~HBIT_7;            // Clear host "available" flag
            PSTAT3 |= 0xC0;                         // Set parasite "Not Full" flag (and NMI flag)
            if (HSTAT1 & HBIT_3) tube_irq|=NMI_BIT; // Raise NMI interrupt if enabled
         }
         //tube_updateints_NMI();
      }
      break;

We should carefully review the rest of the code, so see if there are any similar errors elsewhere.

hoglet67 commented 1 year ago

That fix seems to work, and it now passes the tube transfer test suite (disk 491)

Dave

hoglet67 commented 1 year ago

Fixed in indigo alpha2.