Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8051

General • Re: RP2350B dual core work causing GPIO glitches?

$
0
0
The application is a retro-computing project. It's plugged into the back of a ZX Spectrum (Z80 based 1980s micro, as many here will know).

Core1 is doing a ROM emulation. The loop spins, reading the GPIOs looking for a pattern on the Z80 control bus. When it sees the pattern (MREQ and RD both low) it breaks that spinning loop and checks the address on the Z80's address bus. If the address is in the relevant range it changes the 8 GPIOs connected to the Z80's data bus to outputs and sets them with the relevant data byte. It then spins waiting for MREQ to finish, then puts the data bus GPIOs back to inputs and repeats endlessly. This runs with all interrupts off, and with a 200MHz overclock it's just fast enough. It works fine. This is the hard-realtime side of things. It's speed sensitive because if this fails to deliver a byte to the Z80 in time, the Spectrum will normally crash.

Core0, meanwhile, currently isn't doing anything useful. It sets up the various GPIOs, starts core1 working, then drops into a while(1); (because I haven't written the interesting bit yet). Again, it works fine.

There's a PIO and a DMA working together to indicate a timing window. This is a simple timer which times the gaps between the Spectrum's 20ms screen refreshes. The PIO sets, then resets, a single GPIO for about 30us microseconds every 20ms. That's the only other GPIO action that's going on, and the glitch still happens if I comment it out. So probably not relevant.

I recently caught a glitch on the 'scope. It looks like this:

Image

The test code which produced that didn't have the PIO/DMA thing running, and has core0 looking like this:

Code:

  start_rom_emulation();  sleep_ms( 3000 );  // 3 secs to prime the scope// blip1 goes low at the point the z80 is releasedgpio_put( GPIO_BLIPPER1, 0 );  /* Let the Spectrum run */  gpio_put( GPIO_RESET_Z80, 0 );busy_wait_ms( 3000 );  // let the zx boot  while( 1 )  {    gpio_put( GPIO_BLIPPER1, 1 );  }
The yellow line on the trace is "blipper1" here. It goes low at the point the Z80 is released from reset. The busy wait then runs for 3 seconds, which allows the Spectrum to start up. The cyan line on the trace shows the ROM emulation returning bytes to the Z80. There's an odd little period of inactivity in the middle, which I can't explain, but then it continues and the Spectrum starts up fine. The busy wait ends, the core0 infinite loop enters and the yellow trace goes high.

Then half a second later something odd happens. The ROM emulation appears to stop for maybe 25ms. There's no reason the Z80 should stop or reset at that point, the Spectrum is just sat in a loop waiting for the keyboard to be pressed. But something stalls: either the Z80 does, or the ROM emulation just stops responding. The cyan line is actually the ROM emulation supplying bytes to the Z80, so strictly speaking that's what stops. Maybe there's a glitch and the Z80 jumps off out of ROM space and ends up trying to run code from the Spectrum's RAM for a while?

I was fortunate to get that capture. I power cycled the Spectrum 15 times after that, trying to reproduce, but it was fine each time.

I'll add the ROM emulation code below, exactly as I have it running, comments and all, just in case anyone can see anything wrong with it.

Code:

static void core1_rom_emulation( void ){#ifdef OVERCLOCK  set_sys_clock_khz( OVERCLOCK, 1 );#endif  irq_set_mask_enabled( 0xFFFFFFFF, 0 );  initial_jp_destination = 0;  while( 1 )  {#if 1    const uint64_t mreq_mask = MREQ_MASK;    const uint64_t rd_mask   = RD_MASK;    const uint64_t wr_mask   = WR_MASK;    uint64_t gpios;        /* Spin, waiting for a memory request. (Approx 90ns to 100ns)  */    while( ((gpios = gpio_get_all64()) & mreq_mask) );    /* Pick up the address being accessed (approx 20ns) */    uint64_t address = (gpios & GPIO_ABUS_BITMASK) >> GPIO_ABUS_A0;    /* Is it a read that's happening? (Approx 35ns) */    if( (gpios & rd_mask) == 0 )    {      /* Ignore reads from anywhere other than ROM, the Spectrum still reads its own RAM (Approx 15ns) */      if( address <= 0x3FFF )      {// blip2 is low while we're dealing with a ROM read        gpio_put( GPIO_BLIPPER2, 0 );        /* Pick up ROM byte from local image */        uint8_t data = *(_48_original_rom+address);        /* Set the data bus to outputs */        gpio_set_dir_out_masked64( GPIO_DBUS_BITMASK );        /* Write the value out to the Z80 */        gpio_put_masked64( GPIO_DBUS_BITMASK, (data & 0xFF) << GPIO_DBUS_D0 );        /*         * As of this point the data is on the bus ready for the CPU to read it.         * The read happens 428ns after MREQ goes low. This point is reached         * after approx 300ns to 375ns. With a 270MHz overclock the data is         * consistently ready about 200ns to 220ns after MREQ goes low.         */              /* Wait for the Z80's read to finish */        while( (gpio_get_all64() & mreq_mask) == 0 );        /* Z80 has picked up the byte, put data bus back to inputs */        gpio_set_dir_in_masked64( GPIO_DBUS_BITMASK );gpio_put( GPIO_BLIPPER2, 1 );      }      else      {        /*          * It's a read from RAM, the Spectrum's RAM chips will field it.          * Just wait for the read to finish we don't loop continuously          * while this read is on the Z80 control bus          */        while( (gpio_get_all64() & mreq_mask) == 0 );              }    }  } /* End infinite loop */#endif}

Statistics: Posted by dfrp — Tue Apr 08, 2025 4:30 pm



Viewing all articles
Browse latest Browse all 8051

Trending Articles