To support the additional graphics and the new "SELECT GAME" screen the BIOS of the Videopac+ G7400 is modified at 153 bytes. To make room for this modifications the routines for bit-fields and random number generation were removed.
Here I present vpplus.a48 to show how to use the Videopac+ G7400. Most of the code is quite simple and not explained further. It displays text with different attributes. Use the key "C" to toggle conceal mode, "B" to box mode, "L" to toggle blinking and "V" to display a VDC character over the boxed text.
The new hardware consists of the EF9340/EF9341 display processor designed by Thomson Semiconductors. I have found a data-sheet at Alldatasheet.com. You have to enter EF9340 into the search field yourself, a direct link did not work for me. If you know other sources please let me know.
The chip is designed for Teletext like displays. It can display a 40×24 text mode with 8 colors. The size of the chars are 8×10 pixels. It is possible to redefine up to 96 chars with default background color and another 96 chars with explicit background color. The first line of the display is called service row and quite independent from the rest of the display. The chip supports 2 different kind of attributes, parallel and serial. Parallel attributes can be set with every char, changing serial attributes requires one char space. Parallel attributes are text color, double height and width, inverted display, blinking. Block graphic chars support background color as parallel, for normal chars the background color is a serial attribute. Other serial attributes are concealed, box mode and underlining. Concealed chars can be hidden by setting a control bit. In box mode it is possible to make parts of the display transparent. This is not used on the Videopac+ G7400, you can only use box mode to turn the screen black outside the box zone. If pin B of the cartridge is not grounded even the VDC graphics are blanked outside the box zone. This can be used to apply the black border that is normally around plus graphics to VDC graphics. On o2em you can emulate this effect by putting the ASCII string "OPNB" at 040Ch.
To find out on what kind of machine your program is running call
plusselectgame instead of selectgame. Due to a
clever positioned nop both routines are identical on the
non-plus Videopac. On a Videopac+ G7400 the program continues in
bank 1, not in bank 3 as usual. There you can set up some
background graphics just like the games which were re-released for the VP+.
After that you can jump to plusstart which simulates
the result of the normal selectgame routine. Instead of
setting up just one background for the whole game you could also just set a
flag in RAM and use this later to display VP+ graphics.
The VP+ graphics is always behind all other graphic objects. To be able
to see the VP+ graphics it is possible to define any combination of the 8 VDC colors as
transparent. This is done by a routine called plusmode. Every
bit in R7 corresponds to a VDC color. If the bit is 0, the color will be
transparent. With A you can set the luminance of the 8 VP+ colors in a
similar way, if the bit is 0 the color gets brighter. Any object drawn in a
bright color is active for collisions with normal videopac objects. The
collisions are flagged as external, vdc_coll_ext. A shortcut to
hide all VP+ graphics is called plushide.
Before you can access the VP+ graphic registers you have to call
plusenable, just like for VDC and external RAM. Then you can
call plusdata to draw chars on the screen. In R7 you put
the ASCII code of the char you want to draw. From 000h-01Fh there are some
accented chars. The range from 020h-07Fh is mostly normal ASCII. The chars
0A0h-0FFh are user definable. This leaves 080h-09Fh for the serial
attributes.
In R6 you have to put the parallel attribute for the char. Bits 0-2 define
the color of the char. Setting bit 3 (col_patr_stable) prevents
the char from blinking. If bit 4 (col_patr_dhght) is set the
char is displayed with double height. To double the width set bit 5
(col_patr_dwdth). The EF9340/41 chips have some limitations
when doubling chars, they can't display top and bottom parts in the same
line and left and right parts in the same column. With bit 6
(col_patr_invrt) it is possible to invert the char.
Setting bit 7 (col_patr_blck) changes to block graphics.
Bits 4-6 of the attribute are now the new background color for the rest of
the current line, so you can neither double nor invert block gfx chars.
Bit 3 still prevents blinking. The char byte has a new meaning, too. From
000h-07Fh bits 0-5 form a 2×3 bitmap. If bit 6
(plus_blck_full) is cleared there are small lines between the
blocks, if it is set the blocks touch each other. 080h-09Fh are marked as
ILLEGAL in the data-sheet, so do not use them. 0A0h-0FFh are the second set of
user definable chars, they have the background color as parallel attribute.
By calling pluscmd you can send several commands to the VP+
graphics engine. Among them are commands to move the cursor.
To set
the cursor to the first column in any line set R7 to
plus_cmd_brow. Put the line number into R6. The first line
(service row) is special, its position is 01Fh. The second line is numbered
0 (or 020h). Similar is plus_cmd_loady, the y position is set,
but this time the x position is unchanged. To set the x position of the
cursor set R7 to plus_cmd_loadx. Set R6 to 0 for the first
column, to 1 for the second column etc. The last command to move the cursor
is plus_cmd_incc. This one advances the cursor one char.
This command sets the R register. It has its own routine called
plusloadr. It takes the display mode in A. This mode is composed
by 8 single bits. Setting bit 7 (plus_loadr_blnk) enables the
blink mode, everything where col_patr_stable is not set blinks.
Bit 6 in the R register switches between 50 and 60Hz mode. This is handled by
the BIOS, it gets always set on my machine which means 50Hz. Bit 5 should
always be left to 0, it changes the width of the HSYNC pulse. Setting bit 4
(plus_loadr_crsr) enables a visible cursor. Bit 3
(plus_loadr_srow) enables the display of the service row (the
first line), bit 0 (plus_loadr_dspl) enables the rest of the
display. When setting bit 2 (plus_loadr_conc) all chars with the
col_satr_conc attribute set are hidden. Setting bit 1
(plus_loadr_box) hides all chars except the ones with
col_satr_box set.
This routine is only safe when inside the VBLANK period. Otherwise parts of
the screen memory get trashed. So always call waitvsync
immediately before using plusloadr.
This command sets the line number which gets displayed as second line. So
you can scroll lines very easily, but the first line (service row) always
stays as the first line. Set the line number into bits 0-4 of the parameter
byte and set bit 5 (plus_loady0_zom) to display every line
(except the first) with double height. Characters which have
col_patr_dhght set are doubled again, so they are now 4 times
as high as normal.
There are 2 different ranges for user definable chars. One with doubling
and inverting as parallel attributes and one with background color. To
define a char you have to put it under the cursor. Normally the cursor advances
to the next screen position when printing a char. To turn this off send the
command plus_cmd_loadm with the parameter
plus_loadm_wrni. Then print the char you want to redefine. Now
use plus_cmd_loadm to switch to plus_loadm_wrsl. The
next 10 bytes written with plusdata define the char. To
redefine the next char switch back to plus_loadm_wrni, print it,
switch to plus_loadm_wrsl and send the next 10 char bytes. To
put the cursor back to auto advance use plus_loadm_wr. Here is
some code to redefine the char 0A0h into a smiling face:
mov r7,#plus_cmd_loadm
mov r6,#plus_loadm_wrni
call pluscmd ; do not move cursor
mov r6,#000h
mov r7,#0A0h
call plusdata ; print char to define
mov r7,#plus_cmd_loadm
mov r6,#plus_loadm_wrsl
call pluscmd ; char bitmap follows
mov r2,#chardata & 0FFh
mov r3,#10
.char call getchar
mov r6,a
mov r7,a
call plusdata
inc r2
djnz r3,.char
; back to normal
mov r7,#plus_cmd_loadm
mov r6,#plus_loadm_wr
call pluscmd ; draw normal chars
[...]
; get char data
getchar mov a,r2
movp a,@a
ret
chardata
db 00111100b
db 01000010b
db 10000001b
db 10100101b
db 10000001b
db 10100101b
db 10011001b
db 10000001b
db 01000010b
db 00111100b
If you have to define a lot of chars it is faster to turn off the display
by clearing plus_loadr_dspl and plus_loadr_srow.
That way the chip has more bandwidth available on its bus.
For any of the aforementioned plus_loadm_ write modes there
is a corresponding read mode, but there is no routine to read the data in
the BIOS. So you have to read it manually. The data-sheet is not very clear
is this aspect, it seems that the chip needs a dummy read from its TB
register to fetch the data. Additionally you have to check the busy flag by
calling plusready. Here is some example code how to use
plus_loadm_rdni. This is just my test code, it is not included
into any demo program.
mov r7,#plus_cmd_loadm
mov r6,#plus_loadm_rdni
call pluscmd
call plusready ; wait until mode switched
mov r0,#vpp_tb_rd
movx a,@r0 ; trigger read
call plusready ; wait until read finished
mov r0,#vpp_ta_rd
movx a,@r0 ; TA
mov r2,a
inc r0
movx a,@r0 ; TB
mov r3,a
If you need the access the VPP as fast as possible you can access the
registers directly. This avoids the call and ret
overhead. First you have to wait until the chip is ready. Then you can send
one command with parameters to the chip. The command/parameter combination
is 16 bits wide. The VPP executes the command when the TB register
part is written. So you need to write to the corresponding TA register
first. The chip is busy until the command is finished, but you only need to
check this before trying the next command. The following piece of code
draws an A at the position R3/R4:
; position the cursor at the beginning of line R4
mov r0,#vpp_busy ; busy flag at bit 7
.busy1 movx a,@r0
jb7 .busy1 ; wait for mailbox ready
mov r1,#vpp_ta_cmd ; command register
mov a,r4
movx @r1,a
inc r1
mov a,#plus_cmd_loady
movx @r1,a ; vpp_tb_cmd
dec r1
; position the cursor at column R3
.busy2 movx a,@r0
jb7 .busy2 ; wait for mailbox ready
mov a,r3
movx @r1,a ; vpp_ta_cmd
inc r1
mov a,#plus_cmd_loadx
movx @r1,a ; vpp_tb_cmd
; write a white 'A'
.busy3 movx a,@r0
jb7 .busy3 ; wait for mailbox ready
mov r1,#vpp_ta_wr ; write to data register
mov a,#col_plus_white ; attribute byte
movx @r1,a
inc r1
mov a,#041h ; char 'A'
movx @r1,a ; vpp_tb_wr
dec r1
Some things were still unclear, but with the help of René van den Enden and some more experimentations I can now answer them:
The VDC is always in front. VDC graphics outside box mode can be blanked if pin B of the cartridge is not grounded. To use this feature with o2em you have to put "OPNB" at 040Ch into bank 1.
Only 4 KByte are used, two of the RAM chips are only used as 1 KByte chips. The reason is probably that 2 KByte SRAM chips are much more common than 1 KByte.
It does not, it was a very stupid programming error on my side.