MZ-700 – PCG700 – Programming

PCG700 Programming

HAL Laboratory

General

The RAM of the PCG700 allows to modify up to 256 characters of both character sets. The PCG700 can process only the upper 128 characters of each character set. The lower 128 characters of each character set cannot be modified by the PCG700. This means that the character codes $00 – $7F of each character set cannot be changed – they remain always active; but the character codes $80 – $FF can be changed.

As known, the MZ-700 has two character sets, each having 256 characters. Both character sets reside in one ROM chip having a capacity of 4 kb. If you compute:
2 character sets x 256 characters x 8 bytes ( each character needs 8 dots x 8 rows. Look at this page for more details ) then you get 4096 bytes = 4 kb.

The 256 characters of the PCG700 use:
2 character sets x 128 characters x 8 bytes = 2048 bytes = 2 kb.

If you use a special programming technique then all dots of the screen can be set as needed by modifying each character matrix to be displayed on the screen.

The advantage of this method ( point-to-point-positioning control / control of a single dot ) is it is much more faster than a bitmap graphic, because the CPU moves 64 bytes in a single step ( bitmap graphic only 8 bits ). And, you do not have to solder anything or to cut wires, copper tracks, etc. on the MZ-700’s board.

The HSW-switch must be in the position PCG ( ON ) and the jumper SSW must be set to the position “ON”. This enables the PCG700 to be controlled by software. For more information about the setting of the jumpers and switches read “PCG700 Operation” now.

The PCG700 uses memory mapped I/O to be controlled by software. This means, the software uses simple I/O commands to control the PCG700. The ports exclusively used for all functions are $E010, $E011, and $E012. Note These ports are exclusively allocated for the PCG700 and cannot be used by other expansions while using the PCG700. The meaning and usage of all ports are described later on this page.

Bank switching must be done prior to be able to access the ports and/or the V-RAM. Both can be activated by the commands OUT ($E3),A or OUT ($E4),A.

Ports control

The following table gives an overview about the ports used by the PCG700:

Port Usage
$E010 Data I/O
$E011 RAM addressing; lower address part
$E012 RAM addressing; upper address part
Control port bits

Port $E012 is used to control the PCG700. All bits are write only. The meaning of the control bits follows:

Port Bit active Function
$E012 0 – 1 High upper address part
2 Low / High CG select
0 = ROM0 ( char. set 1 )
1 = ROM1 ( char. set 2 )
3 Low Software control
0 = on
1 = off
4 High Strobe
( data at all ports are valid )
0 = invalid
1 = valid
5 Low / High Copy bit
0 = copy data from $E010
1 = copy from ROM
6 – 7 unused
PCG700 control flow

Using the PCG700 from BASIC

You can put each of the 8 bytes of the 8 x 8 matrix into DATA commands.

Example:

7
6
5
4
3
2
1
0
 Bit 
 Byte  0 
 Code $10
$7E
$14
$3E
$55
$49
$32
$00

Meaning of “Code”:

A “” represents a binary 1.  A “” represents a binary 0.

i.e. Byte 6 = 00110010 ( binary ) = Code $32 ( hex ).

All codes written in BASIC DATA lines are:

DATA 16, 126, 20, 62, 85, 73, 50, 0 ( decimal ) or
DATA $10, $7E, $14, $3E, $55, $49, $32, $0 ( hexadecimal )

How to program the PCG700 by BASIC

The character in the example shown above shall be transferred now into the PCG-RAM by BASIC. The character can have a code between 128 and 255. The following example uses the code 239.

The following HuBASIC program transfers the character from the example shown above into the PCG RAM0:

BASIC command Function
10 REM PROGRAM 1 CHARACTER ONLY
20 CD = 239 = character code
30 RC = CD – 128 computation for RAM0
40 FOR I = 0 TO 7 processes 8 bytes
50 AD = RC * 8 + I computes address for ROM0
60 READ A reads 8 bits
70 POKE &HE010, A outputs data
80 POKE &HE011, AD AND 255 outputs lower address part
90 POKE &HE012, INT ( AD / 256 ) + 16 outputs upper address part
and sets strobe
100 POKE $HE012, 0 resets strobe
110 NEXT I next 8 bits
120 END
130 DATA 16, 126, 20, 62, 85, 73, 50, 0 8 x 8 matrix

In this example the display code 239 shall be modified ( BASIC line 20 ). The RAM0 shall be used ( RAM address area 0 – 128 ). To this the value 128 is to be subtracted from the character code 239 ( line 30 ). 239 – 128 = 111. The first address in RAM0 is computed by 111 * 8 = 888; the last is 111 * 8 + 7 = 895 ( line 50 ). The data must be transferred by the port $E010 ( line 70 ) and is read prior the transfer into the variable A by line 60 ( data are defined in line 130 ).

The RAM0 is addressed by computing the address in the variable AD into a lower and upper part ( lines 80 and 90 ). The lower part is written into the port $E011 by line 80; the upper part by line 90. The PCG is informed that all data written to its ports are now valid by setting the strobe bit 4 ( line 90: by adding 16 ). The programming of the PCG is finished by resetting the strobe bit 4 by line 100. The PCG will not work properly if the strobe bit 4 isn’t reset ! After all the PCG is programmed and the RAM0 will display the new character if the display code 239 is addressed.

The following HuBASIC program copies one character from the MZ-700’s CG-ROM into the PCG RAM0:

BASIC command Function
10 REM COPY 1 CHARACTER ONLY
20 CD = 163 = character code
30 RC = CD – 128 computation for RAM0
40 FOR I = 0 TO 7 processes 8 bytes
50 AD = RC * 8 + I computes address for ROM0
60 POKE &HE011, AD AND 255 outputs lower address part
70 POKE &HE012, INT ( AD / 256 ) + 16 + 32 outputs upper address part
and sets strobe and copy bit
80 POKE $HE012, 0 resets strobe
90 NEXT I next 8 bits
100 END

This example copies the character related to the display code 263 from ROM0 into the PCG RAM0. It is very similar to the previous example except that the copy bit 5 is set by line 70. Adding of 32 invokes the copy process.

The following HuBASIC program transfers 256 characters into the PCG RAM0:

BASIC command Function
10 REM TRANSFER AN OWN CHARACTER SET
20 FOR J = 128 TO 255 : RESTORE processes all characters
30 CD = J – 128 : GOSUB 60 computation for RAM0
40 CD = J : GOSUB 60 computation for RAM1
50 NEXT J : END next character
60 FOR I = 0 TO 7 : READ A processes 8 bytes
70 AD = CD * 8 + I computes address
80 POKE &HE010, A outputs data
90 POKE &HE011, AD AND 255 outputs lower address part
100 POKE &HE012, INT ( AD / 256 ) + 16 outputs upper address part
and sets strobe
110 POKE $HE012, 0 resets strobe
120 NEXT I : RETURN next 8 bits
130 DATA 24, 60, 126, 219, 255, 36, 90, 165
140 DATA 165, 90, 36, 255, 219, 126, 60, 24 8 x 8 matrix

How to program the PCG700 by Assembler

The following routines are examples to show the process of how the PCG700 can be programmed by assembler. The first routine transfers 8 bytes of the matrix of one self-designed character into the RAM0 of the PCG700. Your matrix must be in any RAM area of the MZ-700 and the register HL must point to the first byte of this area prior to the call of this routine. The matrix table can be designed like the one as shown for BASIC ( of course, you do not use DATA commands, but you put the matrix bytes sequentially into your table ).

For both examples the accumulator register A must be set to the display code prior to the call of the routines. This code has the same value as the PCG700 RAM code or the CG-ROM0 code of the MZ-700 ( in example 2 ).

Both routines are designed in that way so that you can use directly the display code ( $80 – $FF ) or the computed PCG700 RAM0 code ( = display code minus $80 ). No matter which code you use, both codes will be addressed correctly.

; PROGRAM 1 CHARACTER FROM YOUR MATRIX TABLE INTO PCG700 RAM0
; A = DISPLAY/RAM CODE ( can be e.g. 239 or 239-128=111... )
; HL = POINTER TO YOUR MATRIX TABLE IN THE MZ-700 RAM
F5     PRG1CH: PUSH AF        ; save display/RAM0 code
E5             PUSH HL        ; save HL ( HL will be used next )
E5             PUSH HL        ; save me the matrix table pointer
87             ADD  A,A       ; multiply by 2
6F             LD   L,A       ; get result into register L
2600           LD   H,0       ; init H 
29             ADD  HL,HL     ; multiply by 2 = x4
29             ADD  HL,HL     ; multiply by 2 = x8 it is now the
                              ; absolute PCG700 RAM0 address
EB             EX   DE,HL     ; get address into register DE
E1             POP  HL        ; get address of your matrix table
0608           LD   B,8       ; init DJNZ counter for 8 matrix bytes
7E     P1CH1:  LD   A,(HL)    ; get 1 byte of your matrix table
3210E0         LD   ($E010),A ; output matrix byte by port $E010
7B             LD   A,E       ; get lower address into register A
3211E0         LD   ($E011),A ; output lower address by port $E011
7A             LD   A,D       ; get upper address into register A
C610           ADD  16        ; add strobe
3212E0         LD   ($E012),A ; output all to port $E012
7A             LD   A,D       ; prepare A
                              ; to close operation of 1 matrix byte
3212E0         LD   ($E012),A ; reset strobe ( closes operation )
13             INC  DE        ; PCG700 RAM0 matrix table pointer + 1
23             INC  HL        ; pointer + 1 for your matrix table
10EA           DJNZ P1CH1     ; process next matrix byte if any
E1             POP  HL        ; restore HL ( to callers contents )
F1             POP  AF        ; restore AF ( to callers contents )
C9             RET            ; goback to caller

The following example copies one character from the MZ-700’s CG-ROM0 ( character set 1 ) into the PCG700 RAM0. If you want to copy from the CG-ROM1 ( character set 2 ) into the RAM1 then additional you have to set bit 2 of the port $E012 prior to the output to this port. To this e.g. you can modify the instruction ADD 48 to ADD 52.

; COPY 1 CHARACTER FROM MZ-700 CG-ROM0 INTO PCG700 RAM0
; A = DISPLAY/ROM0/RAM0 CODE ( can be e.g. 239 or 239-128=111... )
F5     COP1CH: PUSH AF        ; save display/ROM0/RAM0 code
E5             PUSH HL        ; save HL ( HL will be used next )
87             ADD  A,A       ; multiply by 2
6F             LD   L,A       ; get result into register L
2600           LD   H,0       ; init H 
29             ADD  HL,HL     ; multiply by 2 = x4
29             ADD  HL,HL     ; multiply by 2 = x8 it s now the
                              ; absolute ROM0/RAM0 address
EB             EX   DE,HL     ; get address into register DE
0608           LD   B,8       ; init DJNZ counter for 8 matrix bytes
7B     COP1C1: LD   A,E       ; get lower address into register A
3211E0         LD   ($E011),A ; output lower address by port $E011
7A             LD   A,D       ; get upper address into register A
C610           ADD  48        ; add strobe & copy flag
3212E0         LD   ($E012),A ; output all to port $E012
7A             LD   A,D       ; prepare A
                              ; to close operation of 1 matrix byte
3212E0         LD   ($E012),A ; reset strobe ( closes operation )
13             INC  DE        ; matrix table pointer + 1
10EA           DJNZ COP1C1    ; process next matrix byte if any
E1             POP  HL        ; restore HL ( to callers contents )
F1             POP  AF        ; restore AF ( to callers contents )
C9             RET            ; goback to caller

Special thanks to Hideki / Japan for the translations from the PCG700 Manual

More about the PCG700:
Select <Overview> <Installation> <Operation> Programming <PCG-AID><PCG700 Games>