Close

6850 Emulation with a PSoC (Part 3)

A project log for 3-Chip Z80 Design

Combining a Z80 retro design with a modern PSoC CPU.

land-boardscomland-boards.com 10/20/2019 at 16:370 Comments

In this log we will look at interrupts for the M6850. [Edit: this is a helpful page to understand the three interrupt modes supported by the Z80. Grant's code uses Interrupt Mode 1]. We left the compilation broken for interrupts and we need to fix those by creating the code and handing the differences vs the SIO. We also don't know exactly how Grant is handling interrupts. We do know from Grant's source code that he's apparently using them for receive and not for transmit. One difference between the Z80 peripheral chips and M6800 family parts like the M6850 is that there is no interrupt vector produced for the M6850 type of part.

The Z80 handles the lack of interrupt vector by having a special vector of 0xFF for devices which are not present. This seems to rely on the data bus floating high. We can probably do better and send out a 0xFF with a proper interrupt acknowledge cycle. Let's make this assumption and see if it works.

The errors that the compiler is producing now are both related to missing functions/values since they are not yet implemented for the M6850.

The SIO reads the value of the Interrupt vector from one of the control registers. As noted there's no such register in the M6850 so let's fix that. The error is coming out of the Z80IOHandle code:

    if ((ioCrtlRegVal & IACK_MASK) == IN_IACK_CYCLE)
    {
        SioReadIntRegB();
        return;
    }

Set the #define to conditionally remove the SIO code when the SIO is not used. 

The SIO code for the routine is:

///////////////////////////////////////////////////////////////////////////////
// void SioReadIntRegB(void) - Read the Interrupt vector

void SioReadIntRegB(void)
{
    Z80_Data_In_Write(SIO_B_WR2);
    IO_Ctrl_Reg_Write(IO_Ctrl_Reg_Read() & 0xFB);   // Clear IRQ* line
    ackIO();
}

Z80_Data_In_Write(SIO_B_WR2) - returns the interrupt vector to the SIO. The next line clears the interrupt source. We still haven't set the interrupt anywhere so we will need to deal with that, but let's create a flag after we make the equivalent function for the M6850.

 is not defined but we need to replace it with an the proper bit for the M6850. According to the data sheet this is bit 7 of the status register.

For the M6850 the code looks like:

///////////////////////////////////////////////////////////////////////////////
// void M6850ReadIntReg(void) - Read the Interrupt vector

void M6850ReadIntReg(void)
{
    Z80_Data_In_Write(0xFF);
    IO_Ctrl_Reg_Write(IO_Ctrl_Reg_Read() & 0x7F);   // Clear IRQ* line
    ackIO();
}

After adding the function prototype to the Z80_Emul.h file the only compiler error is:

So we are still missing an interrupt #define. That is used in a function in Z80_IO_Handle.c:

void ackIO(void)
{
    IO_Ctrl_Reg_Write(IO_Ctrl_Reg_Read() | CLR_IO_INT_BIT);
}

That is one of the #define values in Z80_SIO_Emul.c. It controls the interrupt hardware from the PSoC to the Z80, so it would be better added to the Z80_IO_Handle.h file. After doing that the PSoC compiles without error.

As a rough measure the M6850 emulator file is 114 lines long as compared to the SIO emulator file which is 444 lines. This shows just how easy it is to create relatively simple peripherals in the PSoC. It's made even easier in this instance since we have a Serial UART emulator already in the SIO software.

In the next log we will see what we missed and fix it so the code runs.

Discussions