Z80 Assembly programming for
the Elan Enterprise 128
What is the Enterprise 128?
The Enterprise 128 is
an 8 bit Z80 system, it's comparable to the Amstrad CPC,however it
has more advanced Memory Mapping which allows more flexible bank
switching, and more advanced graphics
Like the CPC screen it can function at 320x200 at 4 colors, and you
can halve the resolution to get 160x200 with 16 colors... unlike the
CPC, there is a 256 color mode of 80x200
All these modes can be 'half resolution' of 100 vertical pixels
The Enterprise doesn't just have more colors though! compared to the CPC, a
screen that can be split into sections, and each section can be a different
screen mode and color pallete - this can be done with clever interrupts on
the CPC, but the Enterprise does this in hardware, without interrupts or cpu
power used - allowing for far more colorsplits, The color palette is also
better - the regular CPC has 27 possible colors, but the Enterprise has 256
The Basic Enterprise has 64k, but
we'll be focusing on the 256k version
The Enterprise and it's OS supports up to 256x 16k banks for an
insane 4MB of memory (though some may be rom!)
The most basic system supports 64k, but there is also a 128k version
(the EP128)...
There are two special segments... the Zero Segment containing the
RST's, and our program, (loaded at &0000) and the system segment
(loaded at &8000 by default)... around 2/3rds of the system bank
will be used by the OS... the rest will be free.
it's important to notice, ONLY memory banks
in the base 64k (&FC FD FE FF) can be used for video memory.
We can use the Zero page bank if we want... but we must 'request'
ALL other banks from the OS before using them... it will find one,
and tell us what it's allocated - if all the banks are used, it will
give us the spare memory of the system page,
The diagram to the right, shows how the OS allocates memory on
these two systems.
Essentially the internal memory has bank numbers 255-252 (FF-FC)...
as we add more memory, we will get lower and lower numbered banks...
for example a 256k system will have banks down to 240 (F0)
The top bank (255) is used as the system segment... the bottom bank
(number will depend on upgrades) will be the Zero page...
The system will allocate banks in consecutive order... so we won't
use the internal 64k until we have no choice... this means we can be
sure to have it available for Vram!
Low numbers (for example banks 0-4) will be rom.
Bank switching is performed by
simply writing the bank number (Eg &FC) to the ports &BO
&B1 &B2 and &B3 with an OUT command
64k System
128k System
FC
(Zero)
F8
(Zero)
FD
F9
FE
FA
FF
(Sys)
FB
FC
FD
FE
FF
(Sys)
64k
Bank
(Can be Vram) Extended
bank
(Cannot be vram)
Banks witching Ports:
Address
Port
&0000
&B0
&4000
&B1
&8000
&B2
&C000
&B3
Asking for memory... and giving it back
to the OS!
We can ask the OS for memory, and then use it for whatever we
want... if we don't need it any more, we can tell the OS to take it
back!
This is how we get a free VRAM bank... we ask for memory banks,
until we get one >=FC (a 64k internal bank)... This may take a
while, as the OS gives us the low numbered banks first... but once
we get one, we can just free up all the ones we didn't really want!
We use RST 6 to do an EXOS call... and command 24 to request a
segment, and 25 to give it back!
Lets look at the details of these two commands:
EXOS Function 24 - Allocate Segment
This command will request another 16k segment... status reg will be
Zero if succeeded, NZ if another full 16k is not available
If succeeded the segment number will be returned in C... if only a shared
segment was available, the boundary will be in DE Parameters:
none Returns:
A=status C=segment number DE=EXOS
boundary within this segment (if returned is a shared segment, otherwise
&4000)
EXOS Function 25 - Free Segment
This command will free a 16K segment of RAM. The segment must have
been allocated via EXOS function 24.
Parameters:
C=segment
number Returns:
A=status
If we don't
need the OS, we can just use the memory ourselves without
asking...
But if we want it to do Disk reading or other things for us, we
need to play nice!
It all depends on how you plan to use the system, and how worried
you are about compatibility.
Screen Memory
The Enterprise screen memory location
and layout is defined by a LPT block
Each Line contains 16 bytes in the
format below:
Offset
Name
Bytes
Example
Meaning
0
SC
1
256-200
LLLLLLLL
Two's complement of the number of scanlines in this mode line.
Zero means 256 scanlines.
1
MB
1
%01010010
ICCRMMML
I VINT=0, no IRQ
CC Colour Mode=01, 4 colours mode (2/4/16/256)
R VRES=1, full vertical resolution (full/half)
MMM Video Mode=001, pixel graphics mode
L Reload=0, LPT will continue
2
LM
1
11
SSLLLLL
S Special bits in 2 color mode
L Left Margin
3
RM
1
51
SSRRRRR
S Special bits in 2 color mode
R Right Margin
4
VIDADDR
2
&0000
LLLLLLL HHHHHHHH
Memory address of Vram in first 64k of memory (low number banks -
not 128k upgrade)
6
VIDADDR2
2
?
LLLLLLL HHHHHHHH
Second Video Data address - not used in pixel graphics Modes
8
COL0-7
1x8
%00000111
g0 r0 b0 g1 r1 b1 g2 r2
8 palette definitions (8-15 are the same, with FIXBIAS offset)
16
SC
-
-
-
Next line in the LPT block
Keyboard/Joystick
Reading from the keyboard on the
enterprise is easy.
There are 10 rows, from 0-9, we just send the number of the row we want to
port &B5, we then read in from port &B5 to get the status of the
keys in that row.
Reading the Joystick in is also done from port &B5 , however to
select the row we use port &B6.
Row
OUT &B5
IN &B5
IN &B6
bit 7
bit 6
bit 5
bit 4
bit 3
bit 2
bit 1
bit 0
bit
2
bit
1
bit
0
0
LShift
Z
X
V
C
B
\
N
J1-F3
J1-F2
J1-F1
1
Ctrl
A
S
F
D
G
Lock
H
J1-U
2
Tab
W
E
T
R
Y
Q
U
J1-D
3
Esc
2
3
5
4
6
L
7
J1-L
4
F1
F2
F7
F5
F6
F3
F8
F4
J1-R
5
Erase
~
0
-
9
8
J2-F3
J2-F2
J2-F1
6
]
:
L
;
K
J
J2-U
7
ALT
Enter
Left
Hold
Up
Right
Down
Stop
J2-D
8
INS
Space
Rshift
.
/
,
Delete
M
J2-L
9
[
P
@
O
I
J2-R
General
Ports on the Enterprise (&80-&83=NICK)
Port
Purpose
Bits
Bit
Meaning
&80
Fixbias
(Color 8-15 top bits)
%----GRBGR
Top 5 bits of
color 8-16
(bottom BGR bits are 000,001,010 etc up to 111)
&81
Border
Color
Eight bit
colour value which will be displayed outside the margins of all
mode lines.(%GRBGRBGR)
Here's my Hello World example. I couldn't find one, so I had to
write it! It uses the operating system to access the screen and keyboard.
This code was tested using WinApe - which is a CPC emulator, but it
can compile ASM program code just fine
Download this from the sourcecode link at the top of this page!
write "..\RelEnt\program.com"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Hello
World ; ; Show a hello world
message, then read a key ; From the keyboard and
show it. ; ; Screen and keyboard ops
use Enterprise OS calls ; by opening 'stream'
devices to the Keyboard and ; screen ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ORG &00F0
DB0,5 ;type 5 - Binary Program
DW
FileEnd-FileStart
;File length
DB 0,0,0,0,0,0,0,0,0,0,0,0 ;Spacer ; org &0100
FileStart:
LD SP,&100 ;set
the Stack to a safe place
di
ld
c,MODE_VID ;Set
text mode
ld d,0
call ENT_Writevar
ld c,COLR_VID ;Set 2 color
ld d,0
call ENT_Writevar
;Display the just opened
screen
ld a,10 ;
A channel number (1..255)
ld b,1 ;
B @@DISP (=1) (special function code)
ld c,1 ;
C 1st row in page to display (1..size)
ld d,24 ; D
number of rows to display (1..27)
ld e,1 ; E row
on screen where first row should appear (1..27)
call ENT_SpecialFunc
ld de,ENT_Keboardname ; Open the keyboard as stream 11
ld a,11
call ENT_OpenStream ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; INIT
Done ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ld hl,Message
call PrintString ;Print Hello world message
call
NewLine
call
WaitChar ;Wait
for a keypress
push af
ld
hl,Message2 ;Print 'You
Pressed' message
call PrintString
pop af
call
PrintChar ;print
the char the user pressed
call NewLine
di
halt ;stop
execution - I've not figured out how to return to basic!
Message: db 'Hello World!',255
Message2: db 'Key Pressed:',255
PrintString:
ld a,(hl)
cp 255
ret z
inc hl
call PrintChar
jr PrintString
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Functions
for
controling EXOS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ENT_OpenStream: ;Open stream A from
device string DE ;DE should point to a
string like... db 6,'VIDEO;' or db
9,'KEYBOARD;' (replace ; with a colon)
rst 6
db 1 ;open
stream
ret
WaitChar:
push de
push hl
push bc
ld a,11
rst 6
db 5
;read from channel -
result in b
ld a,b
pop bc
pop hl
pop de
ret
PrintChar:
push de
push hl
push bc
ld b,a
ld a,10
rst 6
db 7
;write to channel a
pop bc
pop hl
pop de
ret
NewLine:
ld a,13
call PrintChar
ld a,10
call PrintChar
ret
ENT_readvar: ;readvar
C from enterprise OS
ld b,0
rst 6
db 16
ret
ENT_Writevar: ;WriteVar
C=D to Enterprise OS
ld b,1
rst 6
db 16
ret
ENT_SpecialFunc: ;Special
Function (for displaying screen)
rst 6
db 11
ret ;Device names db [length],'name;'
ENT_Screenname: db 6,'VIDEO:'
ENT_Keboardname: db 9,'KEYBOARD:'