Saturday, 25 August 2018

Displaying the C64 welcome screen on VGA screen


In the previous post we managed to display a static frame stored in SDRAM to a VGA screen.

In this post we are going to take it one step forward and try to display frames rendered from our VIC-II module to a VGA screen.

To View a Video for this Post...

This video explains how to modify our current C64 design to take output the frames from our VIC-II module and display it on a VGA screen.

For a more in detail discussion on the contents of this video, please continue reading...

A recap on the current state of our C64 design

It has been some time since we worked on our C64 design.

In the last couple of posts all efforts was diverted into developing functionality for displaying frames stored in SDRAM to a VGA screen.

Within goal accomplished in the previous post, I think it is time we focus again on our C64 design.

So, let us start by refreshing our minds where we ended off with our C64 design.

When we last worked on the C64 design, it was in a state where we could generate a VIC-II frame with the C64 welcome screen, and store it in SDRAM.

So, with the functionality from the previous post where we could display a frame from SDRAM to a VGA screen, we should be able see the C64 welcome screen displayed on a VGA screen.

One things to mention though is that our design from the previous post expects frames to be at the exact resolution of the VGA monitor you are using. Our C64 design, however, produces frames at a much lower resolution (e.g. something like 404x284).

We will therefore need to modify our VGA block to cater for the resolution produced by our C64 design.

Modifying the VGA output block

As mentioned in the previous section, our C64 block produces frames that is lower in resolution than a typical recent VGA monitor.

On the over hand, since most recent VGA monitors are LCD's, it is best to produce VGA signals having the native resolutions of the VGA screen in question. It just looks better on these screens in native resolutions.

In this post we will therefore output a signal at native resolution and display the C64 output frames in small section on the screen.

This requirement requires a couple of changes to our VGA block design.

The first change is within our Asynchronous FIFO that buffer that buffers pixel data from the AXI clock domain to the pixel clock domain:

     //Reading port
     .ReadEn_in((vert_pos_next > 100)  & (vert_pos_next < 384) &
                                (horiz_pos_next > 100) & (horiz_pos_next < 505)),
     //Writing port.  
     .WriteEn_in(/*state != GET_SET*/(state_shift_reg == STATE_16_SHIFT_STORED | state_shift_reg == STATE_16_SHIFT_SHIFTED) & !buffer_full),
     .Clear_in(/*state == RESET_CYCLE)*/trigger_restart_state == RESTART_STATE_RESTART)

With this change we only enable reads from this FIFO when our VGA signal is at the visible region on the screen.

The visible region is between vertical position 100 and 384 and between horizontal position 100 and 505. This will give as the small 404x284 C64 window on the screen.

We would like our small C64 window to be surrounded by a black border on the screen. To that we need to do the following modifications:

assign out_pixel_buffer_final = (vert_pos > 100)  & (vert_pos < 384) &
                                (horiz_pos > 100) & (horiz_pos < 505)
                                ? out_pixel_buffer : 0;

With this change we output the pixel data from our FIFO if it is within the visible region. For all other positions we output a black pixel.

Adding VGA output to our C64 design

Let us now add VGA output to our C64 design. We do this by first adding the VGA block mentioned in the previous section.

Next, we add the AXI Read block we have developed and used in the last couple of posts.

We will wire up this VGA and AXI read block in a similar way as described previously. Care should however be taken with the AXI Master output port of our AXI read block.

When adding the VGA functionality to our existing C64 design, we will have indeed have two AXI master ports we will need to hookup, whereas our current Processing system only have one AXI slave port configure.

We will therefor need to twig our design a bit to cater for the two master ports.

Start off by removing all AXI helper blocks. I have highlighted them in the following picture:

With these blocks removed, we need to configure our Processing block by double clicking on it, and selecting an extra GP port:

With this option selected, you will see an extra AXI GP port on the processing block:

You can now make use of the designer assistance provided by the IDE to wire up both GP ports.

Just after the wiring up, you will most probably get the following warning:

The IDE will nonetheless allow you to continue, but you will eventually be stopped with an actual error during either the Synthesis or Bitstream generation process. So it is better to try and resolve the warning at this point.

Let us see if we can resolved this warning. We start by opening the Address editor tab within Block design window:

The values in the address editor is used to configure the AXI Helper blocks to decide to which GP port to forward a particular address. But, there is a bit of duplicate mappings here. For instance, the 512MB block range starting at address 0x0 is mapped to both GP0 and GP1.

We can simplify the mapping the following:

Now we have GP0 dedicated to our AXI write block and GP1 dedicated to our AXI read block.

With these changes our design should Synthesise and generate the BitStream without any errors.

The End result

With everything started up, the screen looks as expected:

This is only the Welcome screen with no Flashing cursor.

In Summary

In this post we managed to display the frames produced from our VIC-II module to the VGA screen.

In the next post we will attempt to implement the flashing cursor.

Till next time!