|Z88 Developers' Notes|
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 mapOUT, if call successful:
Fc = 0OUT, 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:
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 + coldistGiven 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 = 12which is at <byte12>. The pixel position within the byte (ie. bit position) is simply:
pixelpos = 7 - (x mod 8) => 5which 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:
; Open graphics window '1', static size of 256x64 pixels, and bind
; 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 a, '1' ; use window '1' for graphics map
call_oz(OS_Map) ; create map width of 256 pixels
ld hl,0 ; dummy address
call_oz(OS_Sci) ; get base address of map area
call_oz(OS_Sci) ; (and re-write original address)
rlc c ; convert MM_Sx to MS_Sx segment
call_oz(OS_Mpb) ; bind hires0 memory into segment
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
; 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 ret
|Dors||The Map Area||Miscellaneous useful routines|