HuC6280Â Assembly
programming for the PC Engine! (TurboGrafx-16)
The PC-Engine uses a super-charged
version of the 65c02... which itself is an improved version of the
6502
Known as the TurboGrafx-16, the PC-Engine is often mistaken for a 16
bit system because of its's speed ang graphical capability.
|
 |
 |
 |
There are various sucessors to the PC
engine, but we'll only be covering the basic model.
|
PC Engine
(TurboGrafx-16) |
| Cpu |
1.79mhz HuC6280 (7.16 MHz fast mode) |
| Ram |
8k |
| Vram |
64k |
| Resolution |
256x239 / 565x242 |
| Sprites |
64 onscreen, 16 per line (16x16 - 32x64) |
| Tilemap |
32x32 (or higher)... max 2048 unique patterns |
| Colors |
612 onscreen (16 per tile/sprite) |
| Sound chip |
HuC6280 6 channel wavetable synthesis |
| CD |
Optional CD drive |
| PSU |
PAD-105: 9V Center Negative (10V Famicom adaptor works)
PAD-124: 10V Center Positive
OTHERS MAY BE DIFFERENT! - see
list here |
|
 |
ChibiAkumas Tutorials
Resources
PC
Engine GT Capacitor list - For repairing the portable PC Engine
The PC-Engine CPU
banking and Memory Map
The PC engine uses an effective 21
bit memory map... Â 13 bits of the address specified, and 8 bits
from the MPR register
The topmost 3 bits are mapped through a Memory Management unit which
maps to Ram/Rom or hardware
This is all a bit confusing, but it's really pretty easy
This Memory management unit has 8 registers, each of which handles a
range of $2000 of the memory map, and a bank from $00-$FF... $FF is
the hardware I/O ... $F8 is the 8k of basic ram... $00 is the first
page of your cartridge rom.
To page in a bank, we need to specify it by 'bit position' (so bank
7 has bit 7 set... so 128)
we load A with the bitmask for that MPR, then use the special
command TAM (transfer A to MPR)
eg: - lets load bank $F8 into MPR page 1 ($2000-$3FFF)
  lda #$F8  ;ram bank
  TAM #2  ;bit 2 for bank 2
(%00000010)
NOTE: The ZeroPage is at $2000 , and the Stack is at $2100
... this is unaffected by the MPR's.... this causes problems in
VASM, where if  we try to write STA $0000 ... the assembler
will optimize it to STA $00
|

| MPR |
Setting |
From |
To |
MPR Page |
| 0 |
1 |
$0000 |
$1FFF |
$FF (I/O) |
| 1 |
2 |
$2000 |
$3FFF |
$F8 (RAM) |
| 2 |
4 |
$4000 |
$5FFF |
???? |
| 3 |
8 |
$6000 |
$7FFF |
???? |
| 4 |
16 |
$8000 |
$9FFF |
???? |
| 5 |
32 |
$A000 |
$BFFF |
???? |
| 6 |
64 |
$C000 |
$DFFF |
???? |
| 7 |
128 |
$E000 |
$FFFF |
$00 (Card Rom) |
|
IO Ports
| From   |
To
Â
    |
Repeated
every n bytes |
Purpose |
| $0000 |
$03FF |
4Â |
VDC (Vram access and screen
setup) |
| $0400 |
$07FF |
8Â |
VCE (Palette selection) |
| $0800 |
$0BFF |
|
Sound Processor |
| $0C00 |
$0FFF |
2Â |
Timer |
| $1000 |
$13FF |
1Â |
I/O Port (Joypad) |
| $1400 |
$17FF |
4Â |
Interrupt Control |
| $1800 |
$1FFF |
|
unused |
| Address |
|
Purpose |
Bits |
Detail |
| $0000 |
|
GPU Reg Select (ST0) |
NNNNNNNN |
reg N |
| $0002 |
|
GPU Data L (ST1) |
LLLLLLLL |
Data L |
| $0003 |
|
GPU Data H (ST2) |
HHHHHHHH |
Data H |
| $1000 |
|
Joypad (Write) |
------CS |
C=CLR S=SEL |
| $1000 |
|
Joypad (Read) |
-C--DDDD |
C=Country D=Joypad Data |
| $1402 |
|
Interrupt Disable |
-----T12 |
T=Timer interrupt request, 1=
IRQ1, 2=IRQ2 |
| $1403 |
|
Interrupt request |
-----T12 |
T=Timer interrupt request, 1=
IRQ1, 2=IRQ2 |
| $1C00 |
|
Timer Reload |
-CCCCCCC |
C=Counter |
| $1C01 |
|
Timer Control |
-------S |
Timer Start/Stop |
The PC-Engine Graphics system
The PC Engine graphics hardware has 64k of ram... but it's
designed for 128k... it's controlled by a set of registers... we
have 3 hardware ports we use to control the hardware... these are
usually memory mapped to $0000 ... but we also have special commands
to quickly write fixed values to the graphics system
We ALWAYS write data to the graphics system registers in HL byte
pairs... Little Endian, so low byte first.
To write data to the memory we set the address we want to write to
with MAWR... but please note , we're only setting the last 16 of the
17 bits... for example, if we set MAWR to $3FFF (%11111111111111),
the actual memory address will be %111111111111110
The effect is, that there are 2 bytes at VRAM $0000... and two
bytes at VRAM $0001 ... and these bytes DO NOT OVERLAP!
|
| Memory address |
Command |
Purpose |
| $0?00 |
ST0
xx |
Select
Register
xx |
| $0?02 |
ST1
xx |
Reg
Val
L=xx |
| $0?03 |
ST2
xx |
Reg
Val
H=xx |
|
Lets write &6543 to 'Byte Pair' at memory address &1234 (remember we
always write in pairs):
      st0 0  Â
      ;Select Register 0
- to select memory address to write to
      st1 $34  Â
   ;Low byte of the memory address we
want to write
      st2 $12  Â
   ;High byte of the memory address we
want to write
      st0 2  Â
      ;Select Register 2
- to actually write data
      st1 $43  Â
   ;Low byte of data to put in memory
      st2 $65  Â
   ;High byte of data to put in memory
Graphics Registers
| Reg |
Name |
Meaning |
Bits |
| 00 |
MAWR |
Memory Address Write |
|
| 01 |
MARR |
Memory Address Read |
|
| 02 |
VRR/VWR |
Vram Data Write / Vram Data Read |
|
| 03 |
|
|
|
| 04 |
|
|
|
| 05 |
CR |
Control |
- - - IW IW DR TE TE BB SB EX EX IE IE IE IE (BB=
Background on) (SB=Sprites on) |
| 06 |
RCR |
Scanning Line Detection |
|
| 07 |
BXR |
BGX Scroll |
|
| 08 |
BYR |
BGY Scroll |
|
| 09 |
MWR |
Memory Access Width |
- - - - - - - - CM SCR SCR SCR SM SM WV WVÂ |
| 0A |
HSR |
Horizontal Sync |
|
| 0B |
HDR |
Horizontal Display |
|
| 0C |
VPR |
Vertical Sync |
|
| 0D |
BDW |
Vertical Display |
|
| 0E |
BCR |
Vertical Display End Position |
|
| 0F |
DCR |
Block Transfer Control |
|
| 10 |
SOUR |
Block Transfer Source Address |
|
| 11 |
DESR |
Block Transfer Destination Address |
|
| 12 |
LENR |
Block Transfer Length |
|
| 13 |
SATB |
VRAM-SATB Block Transfer Source |
|
Vram Layout
Memory in the Vram is not entirely fixed in purpose, this means
you can have weird effects, like using the same memory area for your
Tilemaps - and tile definitions (Patterns)... this is totally
useless, as one will corrupt the other,
but we have to understand it's possible to understand the memory...
as stated before, each address has 2 bytes...
A Pattern (tile definition) is 32 bytes in size (4 bitplanes, 8
lines)... and because each memory address in the Vram map contains 2
bytes... the pattern will take up 16 memory addresses... this means
tile 0 starts at $0000... and tile 1 is at $0010
NOW... the TileMap has to be at $0000 .. and it takes AT LEAST $0400
(it's minimum size is 32x32, and each definition takes 2 bytes)...
for ease, it's probably easiest to start your pattern definitions at
no 256 (memory address $1000) |
| Vram From |
Vram To |
Purpose |
| $0000 |
$03FF |
Min Tilemap (Tiles 0-63) |
| $0400 |
$0FFF |
Possible Tilemap (Tiles 64-255) |
| $1000 |
$7FFF |
Tiles 256-2048 |
| $7F00 |
$7FFF |
SATB
sprite
table |
| $8000 |
$FFFF |
PC-Engine only has 64k, so this is unused |
|
Palette Definitions
The PC engine uses two banks of 16 palettes of 16 colors each
... the first bank is for the tilemap (0-255), the second bank is for the
sprites (256-511)
The Palette entries are controlled by special ports in the IO range in
standard memory:
| Address |
Bits |
Meaning |
|
| $0400 |
00000000 |
Write 0 to reset |
|
| $0402 |
PPPPPPPP |
Palette entry number - Low byte |
|
| $0403 |
-------P |
Palette entry number - High byte |
|
| $0404 |
GGRRRBBB |
Palette color - Low Byte |
|
| $0405 |
-------G |
Palette color - High Byte |
|
We write to $0402 and $0403 to select a palette entry, then define the new
color for the palette entry by a 16 bit definition written to $0404 and
$0405
| Â F |
 E |
 D |
 C |
 B |
 A |
 9 |
 8 |
|
 7 |
 6 |
 5 |
 4 |
 3 |
 2 |
 1 |
 0 |
| - |
- |
- |
- |
- |
- |
- |
G |
|
G |
G |
R |
R |
R |
B |
B |
B |
Tilemap Definitions
As with everything else on the PC engine Vram... each tile
definiton takes one memory address, which contains 2 bytes...
The top 4 bits pppp
define a 16 color palette number from 0-15...
The remaining 12 bits nnnn
nnnnnnnn define the tile number -
as stated, the first 64-256 probably can't be used because they
overlap the tilemap... no's 2048-4095 CANNOT be used, as the memory
these would use would be 64k-128k... and this memory is not
installed in the PC Engine. |
ppppnnnn nnnnnnnn
|
Tile definitions
Tile definitions use 4 bitplanes for 16 colors, and tile
definitions are 8x8 - so 32 bytes ... Data is transfered in Words, and
rather strangely we send bitplane 1+2 of lines, one at a time... then we do
the same for bitplanes 3 and 4
|
Byte 1 |
Byte 2 |
| First
16
bytes |
00111100
01111111
01100011
01100011
01111111
01100011
01100011
00000000 |
00222200
02222222
02200022
02200022
02222222
02200022
02200022
00000000 |
| Second
16
bytes |
00333300
03333333
03300033
03300033
03333333
03300033
03300033
00000000 |
00444400
04444444
04400044
04400044
04444444
04400044
04400044
00000000 |
Sprite Definitions
The basic sprite size is 16x16, though larger sprites can be created by
tilling them, for up to 32x64.... only neighboring sprites can be tilled.
Sprites are NOT in the same format as the tilemap, they are 16x16 with 4
bitplanes, but each plane is sent separately
eg - lets look at a sprite, where all pixels are color 0 or color 15
First
16 bytes
(Bitplane 1) |
1110000000000111
1000000100000001
1000000100000001
0000000100000000
0000000100000000
0000000100000000
0000000100000000
0000000111111100
0011111110000000
0000000010000000
0000000010000000
0000000010000000
0000000010000000
1000000010000001
1000000010000001
1110000000000111 |
Second
16 bytes
(Bitplane 2) |
2220000000000222
2000000200000002
2000000200000002
0000000200000000
0000000200000000
0000000200000000
0000000200000000
0000000222222200
0022222220000000
0000000020000000
0000000020000000
0000000020000000
0000000020000000
2000000020000002
2000000020000002
2220000000000222 |
Third
16 bytes
(Bitplane 3) |
3330000000000333
3000000300000003
3000000300000003
0000000300000000
0000000300000000
0000000300000000
0000000300000000
0000000333333300
0033333330000000
0000000030000000
0000000030000000
0000000030000000
0000000030000000
3000000030000003
3000000030000003
3330000000000333 |
Fourth
16 bytes
(Bitplane 4) |
4440000000000444
4000000400000004
4000000400000004
0000000400000000
0000000400000000
0000000400000000
0000000400000000
0000000444444400
0044444440000000
0000000040000000
0000000040000000
0000000040000000
0000000040000000
4000000040000004
4000000040000004
4440000000000444 |
Sprites are stored in regular vram... the sprite definitions are stored in
special ram which we CANNOT ACCESS...however we can allocate a bank of 256
addresses (each containing one word) called SATB, and then get the hardware
to copy that ram to the special ram... it's suggested you use $7F00 for that
purpose.
To start the copy we just write the address to control reg $13
SATB - Sprite attribute table buffer
The Sprite table allows for up to 64 sprites... each one has 4 words of data
- making 256 words in total... the format is as follows
| Byte |
 F |
 E |
 D |
 C |
 B |
 A |
 9 |
 8 |
|
 7 |
 6 |
 5 |
 4 |
 3 |
 2 |
 1 |
 0 |
Notes |
| 1 |
- |
- |
- |
- |
- |
- |
Y |
Y |
|
Y |
Y |
Y |
Y |
Y |
Y |
Y |
Y |
Y=Ypos (64 is
first visible line) |
| 2 |
- |
- |
- |
- |
- |
- |
X |
X |
|
X |
X |
X |
X |
X |
X |
X |
X |
X=Xpos (32 is
first visible line) |
| 3 |
- |
- |
- |
- |
- |
A |
A |
A |
|
A |
A |
A |
A |
A |
A |
A |
A |
A=Address (Top 10
bits $trueaddress>>5 ) |
| 4 |
YF |
- |
YS |
YS |
XF |
- |
- |
XS |
|
F |
- |
- |
- |
P |
P |
P |
P |
YF=Yflip XF=Xflip YS=Ysize XS=Xsize
F=Foreground
(infront of tilemap) P=Palette |
The PSG Sound generator
The PC Engine PSG has 6 wave based
sound channels... each one uses 32 wave samples, of 5 bits each.
We have to snd some commands to $0804 to tell the PSG we're going to
write data.. then send the data to $0806
We also need to set the volumes correctly!
To the right is a working example which will play a sound wave.
Registers
The PSG is controlled by 10 registers... first a
channel should be selected with Register 0... Channels are numbered
0-5 (written 1-6 in the manuals)
| Reg |
Address |
Meaning |
Channels |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Bit Meaning |
| 0 |
$0800 |
Channel Select |
All |
- |
- |
- |
- |
- |
C |
C |
C |
Channel Select |
| 1 |
$0801 |
Main Amplitude Level |
All |
L |
L |
L |
L |
R |
R |
R |
R |
L/R Volume |
| 2 |
$0802 |
Frequency L |
0-5 |
L |
L |
L |
L |
L |
L |
L |
L |
|
| 3 |
$0803 |
Frequency H |
0-5 |
- |
- |
- |
- |
H |
H |
H |
H |
|
| 4 |
$0804 |
Channel On/Write |
0-5 |
E |
D |
- |
V |
V |
V |
V |
V |
Enable/data
addr... reset or DirectDA… Volume |
| 5 |
$0805 |
LR Volume |
0-5 |
L |
L |
L |
L |
R |
R |
R |
R |
L/R Volume |
| 6 |
$0806 |
Waveform Data |
0-5 |
- |
- |
- |
W |
W |
W |
W |
W |
Wave data (write 32
times) |
| 7 |
$0807 |
Noise Enable |
4-5 |
E |
- |
- |
N |
N |
N |
N |
N |
Enable noise… Noise freq |
| 8 |
$0808 |
LFO Freq |
All |
F |
F |
F |
F |
F |
F |
F |
F |
lfo Frequency |
| 9 |
$0809 |
LFO Control |
All |
T |
- |
- |
- |
- |
- |
C |
C |
lfo Trigger… Control |
|
  Â
lda #0
   sta $0800;Channel Select
   lda #255  Â
;Mixing
   sta $0801
  Â
   lda #1      ;Tone L
   sta $0802
   lda #10     Â
;Tone H
   sta $0803
   lda #%00011111  Â
;Chanel Op - Set 'Data Write'
   sta $0804
   lda #%01011111   ;Chanel
Op - Set 'Reset Write Address'
   sta $0804
  Â
   lda #255
   sta $0805      ;LR Volume
  Â
   ldy #4
ChibiSoundMoreWaves:
   lda #%00011111
   sta $0806
   sta $0806
   sta $0806
   sta $0806
   lda #%00000000
   sta $0806
   sta $0806
   sta $0806
   sta $0806
   dey
   bne ChibiSoundMoreWaves
Â
   lda #%10011111  Â
;Chanel Op - Set 'Play'
   sta $0804
    rts |
| Â |
Buy my Assembly programming book on Amazon in Print or Kindle!

Available worldwide! Search 'ChibiAkumas' on your local Amazon website!
Click here for more info!
|