The map area was designed for graphics purposes. However, no graphics routines were implemented other than a simple horisontal line-write that PipeDream uses. The map is the small area on the right hand edge of the screen to display a picture of what a page looks like in PipeDream, when printed. This region consists of between 0 and 256 pixels across by 64 pixels down. It is theoretically possible to have a 624 by 64 Hires screen, but with current information, graphics are limited to the map area only. It is possible, with extreme care, to write directly to the map memory, by accessing the HIRES0 character set, see the "Hardware layout of the map" section for further details.
Once you have opened a window for the map, say window '1', the system automatically updates the contents of the map to the defined window 50 times a second by the Blink array chip. The map memory is simply hard-wired, and everthing written to it will immediatly be reflected on the screen (if opened via the OS_Map call).
The calls provided here, only allows you to write to the map area, not to read back from it. If you need to know about the contents of the map area, then you should keep a copy of what you write have written to it. The width of the map is limited to 96 pixels in an unexpanded machine. The actual width will always be a multiple of 8, although the widths used by the OS_Map call will be on less than this, ie. 63 refers to an actual width of 64 pixels, numbered 0 to 63. The map call has the following specification:
RST 20H, DEFW $F406
BC = reason code
MP_WR ($01) write a line to the map
MP_DEF ($02) define a map using the Panel default width
MP_GRA ($03) define a map of specific width
MP_MEM ($05) define a map of specific width and associate to application segment
OUT, if call successful:
Fc = 0
OUT, if call failed:
Fc = 1
A = error code:
RC_BAD ($04), bad parameters (errors are generally ignored)
RC_UNK ($03), value of BC is not valid
The various calls to manipulate the map area on the simple line based interface is found at the OS_Map call specification in the System Calls Reference section.
If you are adventurous, have a look at the following examples. Since the map is hardwired, anything written to it will automatically be reflected in the map window. It is possible, and very easy to write graphical routines once the physical layout of the map memory is defined.
The hardware layout of the map
The map on the Z88 have been designed for a maximum of 256 pixels wide and 64 pixels high graphical area. Even though it is a graphical area, its basic organisation is a character based matrix, where each 'character' is defined by eight column bytes from top to bottom. Each 'line' is then defined by the 'characters'. This is why the width of the map area is defined in multiple of 8 (bits). The following illustrates the memory map organisation:
x rows: <byte0> <byte8> <byte16> ... <mapwidth>
<byte1> <byte9> ...
<byte2> <byte10> ...
<byte3> <byte11> ...
<byte4> <byte12> ...
<byte5> ... ...
<byte6> ... ...
<byte7> <byte15> <byte(x)*8+y>
line y: <byte <mapwidth>*8*(y div 8)> <graphics_end>
The above illustration defines the organisation for 'lines' of 'characters'. The width of the map is defined in byte boundaries. The following formula defines the byte position from the base of the map area, defined by a simple (x,y) pixel position, where (0,0) is at the upper left corner of <byte0>.
linedist = (y div 8) * <mapwidth> ; each line is 8 * <mapwidth>
rowdist = (x div 8) * 8 ; step 8 bytes pr. 8 pixels
coldist = y mod 8 ; somewhere in a 'character'
bytepos = linedist + rowdist + coldist
Given a pixel coordinate of (x,y) = (10,4), and a map of 80 pixels wide (10 bytes), the formula would look like this:
linedist = (4 div 8) * <10> => 0
rowdist = (10 div 8) * 8 => 8
coldist = (4 mod 8) => 4
bytepos = 12
which is at <byte12>. The pixel position within the byte (ie. bit position) is simply:
pixelpos = 7 - (x mod 8) => 5
which fits: the second bit (seen from left) in the second byte row.
The following two examples manipulates the map area directly, thereby avoiding the relatively large system overhead of the OS_Map call. Here, you read/write directly to the map area. The two examples show how easy graphics can be implemented on the Z88, as long as you play by the rules and avoid writing beyond the boundaries of the map.
First the base address of the map is fetched, then the memory is paged into segment 2 and the base address of the map is stored at (BASE_GRAPHICS). The following example routine will return an address and a corresponding bit position of the address in the map from a virtual (x,y) coordinate. This is the basic algorithm for manipulating graphics in the map area. The Standard Library contains a complete set of library graphics routines to plot points, draw lines, sprites and scroll the map area contents. All source files are included for evaluation and improvement. These two routines are an extract:
include "memory.def" ; memory call definitions
include "map.def" ; map call definitions
include "screen.def" ; low level screen call definitions
; Open graphics window '1', static size of 256x64 pixels, and bind graphics
; memory into segment 2. NOTE: Only expanded machines may open a 256 pixels
; wide map.
ld a,'1' ; use window '1' for graphics
ld B, MS_S2
ld C, MP_MEM
oz OS_Map ; create a map of 256 pixels
rst OZ_Mpb ; and bind map memory to segment 2
ld (base_graphics),hl ; initialize base address of hires0
; This routine returns the address and bit position of a pixel coordinate (x,y)
; in: hl = (x,y) coordinate of pixel (h,l)
; out: de = address of pixel byte
; a = bit number of byte where pixel is to be placed
; fz = 1 if bit number is 0 of pixel position
; registers changed after return:
; ......hl/ixiy same
; afbcde../.... different
.pixeladdr ld b,l
srl b ; linedist = y div 8 * 256
and @11111000 ; rowdist = x div 8 * 8
ld c,a ; bc = linedist + rowdist
and @00000111 ; coldist = y mod 8
ld de,(base_graphics) ; pointer to base of graphics area
ld e,a ; coldist = graphicsarea + coldist
add hl,bc ; bytepos = linedist + rowdist + coldist
and @00000111 ; a = x mod 8
xor @00000111 ; a = 7 - a