This is an old revision of the document!
Table of Contents
A Guide to Graphics Programming on the SD-8516
This is a general guide to graphics programming. It's not necessarily intended for games, it could be useful for UI programmers as well.
Introduction
The SD_8516 has all the capabilities you would expect from a late 80s “next generation” microcomputer. It also has some powerful features that were usually only available on consoles. You will find that programming graphics on the SD-8516 is fun, easy and rewarding.
For BASIC programmers, you can skip the sections that have assembly code in them. These are most useful for Assembly, Forth and C coders who need to do manual memory management. BASIC covers all of this for you; if you program in BASIC you can just focus on the sections that deal with BASIC commands.
Graphics Modes
The text modes do not have graphics ability. They are solely used for representing text, so we won't discuss them here.
Beyond the text modes are the graphics modes:
| Mode | Resolution | Colors | Description |
|---|---|---|---|
| 3 | 320×200 | 16 | This is a standard 320x200x16 bread-and-butter mode meant to evoke the best of the 8-bit graphics era. |
| 4 | 256×224 | 16 |
format! |
| 5 | 256×224 | 256 | A “Super” version of Mode 4 that can support up to 256 colors. |
| 7 | 320×200 | 256 | An 8bpp version of mode 3. For those that want such a thing. |
| 8 | 128×128 | 16 | An homage to the PICO-8. 128×128 16 color mode. |
| 9 | 512×256 | 256 | Super hi-res double-bank mode (experimental) |
Almost everything that is discussed here will be applicable to all graphics modes. So, we will use Mode 3 as an example and note anything you need to watch out for in other modes.
The Framebuffer
The SD-8516 uses a memory-mapped framebuffer. To render a frame, the Video Chip scans the framebuffer's memory and builds an image from that data. This happens at the refresh rate of your monitor, usually sixty times per second but faster if you have set your monitor to a higher refresh rate.
It's important to understand how the framebuffer works. It's very simple; the bytes in the framebuffer represent pixels. In 8bpp mode, each byte represents the color of one pixel on the screen. In 4bpp mode, each byte represents two pixels; the low-order nibble represents the even pixel and the high-order nibble represents the odd pixel. That means if you POKE a value into one byte, you are treating the screen like it's half resolution; many games worked this way to save code-space, such as Jumpman and King's Quest.
Therefore the BASIC command:
POKE $020000, 1
will set the pixel at 0,0 to palette color 1 in an 8bpp mode, but it will set the pixels at 0,0 and 1,0 to palette color 1 in 4bpp mode.
Here's another example. If you want to set 0,0 to color 1 and 1,0 to color 2, you can do this:
POKE $020000, $21
This sets the low nibble to 1 and the high nibble to 2. Remember, $21 is a hexidecimal number; each place in hex is 4 bits.
Memory Map
The framebuffer for mode 3 is stored in the first 32kb of Bank 2. Some modes, such as mode 5 and 7 use almost all of bank 2. Mode 9 uses both bank 2 and bank 3. Memory which isn't being used can be used by your programs; so if you're using Mode 3, you can store data in the second half of bank 2.
Reading and Writing Pixels
For BASIC, you can PEEK and POKE at framebuffer memory or use the PIXEL/PEXEL commands:
10 LET A = PEXEL(10,10) 20 LET A = A + 1 30 PIXEL 10, 10, A
This program reads a pixel and updates it's color.
Packing and Unpacking pixels
For Assembly and other languages, you will need to pack and unpack the pixel. In Assembly you can use PAB and UAB, but in Forth or other languages you must mask the byte (and do a bit shift for the upper nibble).
In assembly:
LDAL [$020000] ; read the byte at 0,0 UAB ; This command splits AL into AL=low nibble and BL = high nibble.
LDAL $0E ; Set 0,0 to palette color $E (decimal 14) LDBL $0C ; set 1,0 to palette color $C (decimal 12) PAB ; Pack BL into high nibble of AL. AL is now $CE STAL [$020000] ; Stores $CE, the color of two pixels, in the framebuffer.
The stride of a 320×200 screen in 4bpp is 160 bytes. Therefore, if you wanted to deal with a pixel at location X, Y:
LDELM $020000 ; load framebuffer base MUL Y, #160 ; Skip ahead to the correct row ADD ELM, Y MOV T, X AND T, #1 ; T is now whether X was even or odd. SHR X ; Divide ELM by 2. ADD ELM, X ; Skip forward by 1 byte per 2 pixels ; Elm now points to the even and odd pixel you need. LDAL [ELM] UAB ; AL & BL now contain the even and odd pixel color
At this point, if T is 0 you can deal with the color in AL, and if T is 1 you can deal with the color in BL. When you're done,
PAB STAL [ELM] ; Write the pixels back into the framebuffer
For 8bpp modes you don't need to worry about this at all. The byte is the pixel.
