split-screen scroll

This sample loads a single 512x512 image (below) into character RAM, then uses the scroll registers to split the screen into three independently scrolling windows.

The hardware only has a single pair of scroll registers - SCROLL_X and SCROLL_Y. This demo uses a small microprogram running on the coprocessor to split the screen.

The microprogram lets you show three different sections of the screen RAM: in this example, the program shows three slices, each 100 pixels high. The top section doesn't move, the middle section is rotating around the word 'SCREEN' and the bottom section is just scrolling horizontally.

The microprogram running on the Gameduino is quite short: it just watches the YLINE register (in waitline), and loads the SCROLL_X and Y registers at the start of each section. This technique - modifying hardware registers during the frame readout to stretch the hardware - is sometimes called "raster chasing".

start-microcode splitscreen

: 1+    d# 1 + ;
: @     dupc@ swap 1+ c@ swab or ;

: waitline ( u -- ) \ wait until raster is past u
    begin
        dup YLINE c@ =
    until
    drop
;

: loadscroll ( a -- ) \ load SCROLL_X,Y from a
    dup c@ SCROLL_X c! 1+
    dup c@ SCROLL_Xhi c! 1+
    dup c@ SCROLL_Y c! 1+
    c@ dup SCROLL_Yhi c!
    d# 7 rshift SPR_DISABLE c!
;

: main
    begin
        COMM+4 @  waitline  COMM+6 loadscroll
        COMM+10 @ waitline  COMM+12 loadscroll
        d# 300 waitline     COMM+0 loadscroll
    again
;

end-microcode

The demo sketch itself loads the graphic image into RAM, then sets the scroll values in the COMM area to achieve the groovy window scrolling effect.

#include <SPI.h>
#include <GD.h>

#include "splitscreen.h"

/*
 For the splitscreen microprogram, the COMM area holds 8 short words
 that control the 3-way screen split:

 COMM+0   SCROLL_X for top section
 COMM+2   SCROLL_Y for top section
 COMM+4   Y-coordinate of start of middle section
 COMM+6   SCROLL_X for middle section
 COMM+8   SCROLL_Y for middle section
 COMM+10  Y-coordinate of start of bottom section
 COMM+12  SCROLL_X for bottom section
 COMM+14  SCROLL_Y for bottom section
*/

#include "splitscreen_graphics.h"

void setup()
{
  GD.begin();

  GD.copy(RAM_PIC, splitscreen_pic, sizeof(splitscreen_pic));
  GD.copy(RAM_CHR, splitscreen_chr, sizeof(splitscreen_chr));
  GD.copy(RAM_PAL, splitscreen_pal, sizeof(splitscreen_pal));

  GD.wr16(COMM+0, 0);
  GD.wr16(COMM+2, 0);
  GD.wr16(COMM+4, 100);   // split at line 100
  GD.wr16(COMM+6, 0);
  GD.wr16(COMM+8, 140);
  GD.wr16(COMM+10, 200);   // split at line 200
  GD.wr16(COMM+12, 0);
  GD.wr16(COMM+14, (511 & (82 - 200))); // show line 82 at line 200

  GD.microcode(splitscreen_code, sizeof(splitscreen_code));
}

// Set the scroll registers for the middle screen secion to (x, y)
static void scrollxy(uint16_t x, uint16_t y)
{
  GD.wr16(COMM+6, x);
  GD.wr16(COMM+8, y);
}

void loop()
{
  static int i;
  float th = i / 16.;
  scrollxy(55 + 50 * cos(th), 150 + 50 * sin(th));
  GD.wr16(COMM+12, i);
  i++;
  GD.waitvblank();
}