Z88 Developers' Notes
Previous Contents Next

21. The Map Area

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:

OS_Map, PipeDream map control

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_DEL ($04)            delete a map
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:

<graphics_base>, (0,0)

            y columns:
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 Z88 Assembler Workbench 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.
; This routine must be called before using any library graphics routines,
; since they expect the graphics memory to be available through the
; <base_graphics> pointer.
.openmap    ld   b, MS_S2
            push bc                  ; preserve segment specifier
            ld   bc, mp_gra
            ld   hl,255
            ld   a, '1'              ; use window '1' for graphics map
            call_oz(OS_Map)          ; create map width of 256 pixels
            ld   b,0
            ld   hl,0                ; dummy address
            ld   a,sc_hr0
            call_oz(OS_Sci)          ; get base address of map area
            push bc
            push hl
            call_oz(OS_Sci)          ; (and re-write original address)
            pop  hl
            pop  bc
            pop  de
            ld   c,d
            rlc  c
            rlc  c                   ; convert MM_Sx to MS_Sx segment
            call_oz(OS_Mpb)          ; bind hires0 memory into segment
            ld   a,h
            and  @00111111
            or   d
            ld   h,a                 ; base of graphics points at segment
            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
            srl  b
            srl  b              ; linedist = y div 8 * 256
            ld   a,h
            and  @11111000      ; rowdist = x div 8 * 8
            ld   c,a            ; bc = linedist + rowdist
            ld   a,l
            and  @00000111      ; coldist = y mod 8
            ld   de,(base_graphics)  ; pointer to base of graphics area
            ld   e,a            ; coldist = graphicsarea + coldist
            ld   a,h            ;
            ex   de,hl
            add  hl,bc          ; bytepos = linedist + rowdist + coldist
            ex   de,hl
            and  @00000111      ; a = x mod 8
            xor  @00000111      ; a = 7 - a

Previous Contents Next
Dors The Map Area Miscellaneous useful routines