Z80 Assembly programming for
the Sam Coupe (Sam Coup�)
Download
my Sam Coupe Sourcecode and Notes!
As part of my ongoing Z80 tutorials, I've been looking for technically
impressive Z80 based computers that I was not familiar with, but demanded
more attention than the market gave them... after a tip off from a Youtube
viewer, I started looking at the Sam Coupe, and it represents an impressive
Z80 based 8 bit system, that I had only barely heard of (In fact I
incorrecty thougt it was 16 bit!)
What makes the Sam
Coupe Special?
The Sam Coupe came late in the Z80's life - released in 1989, and
discontinued in 1992... they were presumably going after the 16 bit
market, and targeted their system with specs to really compete!
The machine was povided with a 3.5 inch disk drive by default, and
came with a minimum of 256k... what's more, it used a 6mhz Z80...
nearly twice what other systems had... and its screen display is
capable of 256x192 at 16 colors... the same as the MSX, however as
the Sam Coupe screen is part of system memory, it is MUCH faster
than the MSX!
according to my testing, Despite having a 24k screen the Sam Coupe
beats the Amstrad (16k screen, 3.57mhz) for speed doing fill
commands... only the Enterprise is faster (again 16k, but a 4mhz
processor)
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
So what's not to like? well the only 'problem' with the system is
the huge 24k screen seems to have caused some design limitations,
unlike the CPC/Spectrum and Enterprise which bank swap in 16k
chunks, the Sam Coupe swaps in 32k blocks... which would make
porting my ChibiAkumas game pretty time consuming... that said, I
hope to release new games for it in the future, build from the
ground up to work with this limitation!
Unfortunately, the Sam Coupe only sold 12,000 units, so they're
pretty rare now, and I don't own one! fortunately there's a great
free emulator called SimCoupe |
Image taken
from Wikipedia |
ChibiAkumas Tutorials
Useful documents
User Manual
- Basic usage guide
Technical
Manual - You'll want this for programming
SAA1099 -
Sound chip manual
Problems I've come
across!
Sam Coupe disks are 3.5 inch, but
they don't use standard dos format, this means you need to build disk images
with Sam Coupe tools, there's some great ones, such as the "Sam
Coupe Advanced Disk Manager" and "Sam
Coupe Diskimage Manager", but the one I use most is a modified copy of
"Andrew Colliers
Simcoupe DSK manager"
I needed a program that could build a disk image from a script, and I found
I was struggling to get disk images built with the correct "Start address"
(execute address)... Andrews program built disk images from dos, but
unfortunately did not put the code address in, My C++ skills are pretty
rusty, but I managed to build a modified version that puts in a start
address of &8000, and can read the keypresses from a text file, so can
be scripted in the way I wanted... I'll include the source, build and other
useful stuff in the download linked at the top of this page
Bankswitching theory on the Sam Coupe
Controling bank switching on the SAM is done
with two ports, one controls the first 32k of the memory map, the other
controls the second 32k, there's also a port that controls the bank pair
that controls the visible screen (the screen uses 24k so two banks)
The SAM splits its 256/512k into 16k chunks, with the first bank is 0...
Port |
Name |
Description |
Bits |
Bit Meaning |
&FA
- 250 |
LMPR |
Low Memory Page Register |
WHLBBBBB |
B=Bank
&0000-&7FFF... L=Low
rom
off (1=off)... H=High
rom
on (1=on)� W=Write
protect
&0000-&3FFF |
&FB
- 251 |
HMPR |
High Memory Page Register |
MCCBBBBB |
B=Bank
&8000-&FFFF...
C=mode 3
color lookup... M=use
externalmemory
expansion |
&FC
- 252 |
VMPR |
Video Memory Page Register |
OMMBBBBB |
B=Video
Bank...
M=Mode...
O=midi
Io |
You'll notice we only have two bank switching
ports... this is because we switch the memory range in 32k chunks!
even though memory banks are split in 16k.... if we set port 250 to use
bank 0... then the memory range &0000-&3FFF will point to bank
0... but the next bank (&4000-&7FFF) will use the following bank -
bank 1!... The fact we have to work in 32k chunks makes bank switching on
the SAM rather limited compared to other systems where we work in 16k
chunks
Also notice bit 7 of port 251... this allows us to access external memory
upgrades in the range &8000-&FFFF for many megabytes of memory -
we won't be cover them in these tutorials!
Range
|
Page Addr |
Example |
&0000 |
(&250) |
0 |
&4000 |
(&250)+1 |
1 |
&8000 |
(&251) |
10 |
&C000 |
(&251)+1 |
11 |
|
Because we need to swap
banks in 32k chunks it makes it harder to uses memory efficiently on
the SAM... if we page in the screen into one bank, and our sprites
into the other... we have nowhere left for our code!
We will have to work out another way to organize our memory... for
example storing a copy of our sprite handling code in the spare
memory of the screen bank (the screen uses 24k of the 32k bank) |
Keyreading on the Sam Coupe
The Sam Coupe keyboard matrix is based on the Spectrum... just with an
extra 3 lines added to each row.. the extra 3 lines are read from port
&F9
Our reading procedure is basically the same as the Spectrum, but we
have to add in the extra 3 bits from port &F9
The joystick ports on the sam coupe map to the keyboard matrix too, Joy 1
maps to number keys 6-0, Joy 2 maps to 1-5
The Sam Coupe KeyMatrix: (keys in Red are same as
Speccy - BLUE are joystick keys...
Magenta are Sam extras)
Load BC with the address of the required row and keys, and use "IN A,(C)"
Bit-> |
C=
&F9 |
C=
&FE |
B=... |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
%11111110 |
F3 |
F2 |
F1 |
V |
C |
X |
Z |
SHIFT |
%11111101 |
F6 |
F5 |
F4 |
G |
F |
D |
S |
A |
%11111011 |
F9 |
F8 |
F7 |
T |
R |
E |
W |
Q |
%11110111 |
CAPS |
TAB |
ESC |
5 JOY2-L |
4 JOY2-R |
3 JOY2-D |
2 JOY2-U |
1 JOY2-F |
%11101111 |
DEL |
+ |
- |
6 JOY1-L |
7 JOY1-R |
8 JOY1-D |
9 JOY1-U |
0 JOY1-F |
%11011111 |
F0 |
" |
= |
Y |
U |
I |
O |
P |
%10111111 |
EDIT |
: |
; |
H |
J |
K |
L |
ENTR |
%01111111 |
INV |
. |
, |
B |
N |
M |
DEL |
SPC |
%11111111 |
|
|
|
RIGHT |
LEFT |
DOWN |
UP |
CTRL |
Sam Coupe sound registers
The Sam Coupe has 32 registers - though some have no purpose...
write a RegNum to port 511, then a value to port 255 to set one.
Reg |
Purpose |
Bits |
Bit
Meaning |
&00 |
Amplitude
generator 0 |
RRRRLLLL
|
Left / Right
... 15=Max volume
|
&01 |
Amplitude
generator 1 |
RRRRLLLL |
Left / Right
... 15=Max volume |
&02 |
Amplitude
generator 2 |
RRRRLLLL |
Left / Right
... 15=Max volume |
&03 |
Amplitude
generator 3 |
RRRRLLLL |
Left / Right
... 15=Max volume |
&04 |
Amplitude
generator 4 |
RRRRLLLL |
Left / Right
... 15=Max volume |
&05 |
Amplitude
generator 5 |
RRRRLLLL |
Left / Right
... 15=Max volume |
&08 |
Tone
Generator 0 Frequency |
FFFFFFFF |
Higher number
= higher tone |
&09 |
Tone
Generator 1 Frequency |
FFFFFFFF |
Higher number
= higher tone |
&0A |
Tone
Generator 2 Frequency |
FFFFFFFF |
Higher number
= higher tone |
&0B |
Tone
Generator 3 Frequency |
FFFFFFFF |
Higher number
= higher tone |
&0C |
Tone
Generator 4 Frequency |
FFFFFFFF |
Higher number
= higher tone |
&0D |
Tone
Generator 5 Frequency |
FFFFFFFF |
Higher number
= higher ton41 |
&10 |
Octave
register |
-111-000 |
Set tone
register octaves |
&11 |
Octave
register |
-333-222 |
Set tone
register octaves |
&12 |
Octave
register |
-555-444 |
Set tone
register octaves |
&14 |
Frequency
enable |
--543210 |
Tone Channel
enable 0=off |
&15 |
Noise enable |
--543210 |
Noise Channel enable 0=off |
&16 |
Noise Generator |
--11--00 |
00=31k 01=15k 10=7k 11= freq gen 0 (Chn0) / 1
(Chn3) |
&18 |
Envelope
Generator 0 (CH2) |
O-GREEEM |
envelope
controller On / 0= use CH 1 1=timed / Resolution / Envelope shape
/ Mirror other channel |
&19 |
Envelope
Generator 1 (CH5) |
O-GREEEM |
envelope
controller On / 0= use CH 4 1=timed / Resolution / Envelope shape
/ Mirror other channel |
&1C |
Reset and
Enable |
------RE |
Reset
frequency / Enable sound |
SamDos
I had a lot of trouble getting SamDos to work (mostly my own fault) but was
quite frustrated by the fact it seems there is no usable example of how to
use it,
As I now have a working sample, I'm uploading it here to try to help others!
Call SAVE and LOADDIRECT with HL pointing to a filename (see the example at
the top) and DE pointing to a memory destination... A should point to a
Bank!
BC must be bytes to save with the SAVE command!
I will be covering this code in disk ops in detail in my tutorials
very soon!
|
LoadFileName: db "-"
LoadFileNameTrack: db "0000"
db
"."
LoadFileNameCompressed: db "D"
LoadFileNameDisk: db
"0 "
DBASIC EQU &F37D
FOPEN EQU &0F
FCLOSE EQU &10
CREATE EQU &16
BLWRITE EQU &26
BLREAD EQU &27
SETDMA EQU &1A ;Disk transfer address
(Destination/source)
BDOS_INIT EQU &1B
BDOS_RESET EQU &00
BDOS_DiskRESET EQU &0D
BDOS_DefaultDrive EQU &0E
BDOS_GetDefaultDrive EQU &19
;defw &0000 DiscDestRelocateCall_Plus2;not implemented yet!
DiskDriver_Save:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Create a new file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ld (FileErrorSpRestore_Plus2-2),sp
push af
push bc
push de
ld
de,diskerr ;Error handler
ld
(&5BC0),de ;This is called EVERY return from a
Dos call (if error occured or not!)
ld
de,&4B00
ld a,19
ld (de),a
inc de
ld bc,14
ldir
pop de
pop bc
ld ix,&4B00
; ld a,d
; and %110000
pop af
ld (ix+31),a ;31
16K PACE NUMBER START
ld (ix+32),e ;32-33 PAGE
OFFSET (8000-BFFFH) LSB/MSB
ld a,d
and %00111111
or %10000000
ld (ix+33),a
xor a
;34 NUMBER OF PAGES IN LENGTH
ld (ix+34),a
ld (ix+35),c ;35-36
MODULO 0 TO 16383 LENGTH ie file length MOD 16384.
ld (ix+36),b
ld (ix+37),a ;37
EXECUTE PAGE NUMBER if applicable
ld (ix+38),a ;38-39
EXECUTE OFFSET (8000-BFFFH) LSB/MSB if applicable
ld (ix+39),a
xor a
;Before using this hook poke &5BB9 with 0 to overite
existing file.
ld (&5BB9),a
ld ix,&4B00
rst 1
db 132 ;HSAVE - Save file using
IX pointed UIFA
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DiskDriver_LoadDirect:
push hl
ld hl,null
;Disable the relocate
ld
(DiscDestRelocateCall_Plus2-2),hl
pop hl
DiskDriver_Load:
ld (FileErrorSpRestore_Plus2-2),sp
push de
ld
de,diskerr ;Error handler
ld
(&5BC0),de ;This is called EVERY return from a
Dos call (if error occured or not!)
;note - we're not setting this on WRITE command,
we're assuming one read command will happen first!
ld
de,&4B00 ;This points to the UIFA in ram bank
00 - SAMDOS doesn't seem to work right if it's anywhere else!
ld a,19
;This means CODE FILE
ld (de),a
inc de
ld bc,14
;copy the 14 char file name from HL - must be padded with spaces!
ldir
ld ix,&4B00
rst 1
db 129
; HGTHD - Get the file header (loads to IX+80
ld
bc,(&4B00+80+35) ;Get the file size
ld
a,%00111111 ;For some reason
the file sizes seems to be too high, it should be a less than 16384
and b
;It may be my mistake!
ld b,a
pop hl
;This is used when the file is compressed.
; ex hl,de
call null:DiscDestRelocateCall_Plus2
; ex hl,de
push hl
push bc
ld bc,251
;HMPR - High Memory Page Register (251 dec)
in a,(c)
ld (DiskRestoreBank_Plus1-1),a
push bc
ld
de,&4F00
ld
hl,DoActualLoad
ld
bc,DoActualLoad_BlockEnd-DoActualLoad
ldir
ld
de,diskerrSpec-DoActualLoad+&4F00 ;Error
handler
ld
(&5BC0),de ;This is called EVERY return from a
Dos call (if error occured or not!)
pop bc
pop de
pop hl
jp &4F00
DoActualLoad:
and %11100000
or 0:DiskLoadBank_Plus1
out (c),a
ld c,0
ld ix,&4B00
rst 1
db 130
;HLOAD - Load the file
LoadDone:
scf
; OK! set carry flag
LoadDone2:
ret
DoLoadFromBankB:
diskerrSpec:
push af
ld
bc,251 ;HMPR - High Memory Page Register (251 dec)
ld
a,0 :DiskRestoreBank_Plus1
out (c),a
pop af
diskerr:
or a ;Clear
the carry frlag
ret z ; no
error
ld
sp,&0000:FileErrorSpRestore_Plus2
jr LoadDone2
DoActualLoad_BlockEnd:
;UIFA
;db 19
;db
"music.bin
"
;
;ds 80+48
;DIFA
;ds 48
;5BC0H - REPLACE THIS WITH MY OWN ERROR HANDLER!
;UIFA and DIFA have the same format,
;UIFA is provided by user at IX, DIFA is returned by the disk at
IX+80
;0 STATUS/FILE TYPE.
;1-14 FILENAME. 14 characters are allocated
to allow for device
; identification, for example D1;filenamexx.
SAMDOS will strip
; off the device identifier, so the maximum length
of a filename
; is still ten characters.Sa
;15 FLAGS
;16-26 If the file type is 17 or 18 then these bytes contain
the
; type/length byte and the name.
;16 If the file type is 20 then this byte
contains the screen
; mode.
;16-18 If the file type is 16 then these bytes contain the
program
; length excluding variables.
;19-21 If the file type is 16 then these bytes contain the
program
; length plus the numeric variables.
;22-24 If the file type is 16 then these bytes contain the
program
; length plus the numeric variables and the gap
length before
; the character variables.
;27-30 SPARE 4 BYTES (Reserved)
;31 16K PACE NUMBER START
;32-33 PAGE OFFSET (8000-BFFFH) LSB/MSB
;34 NUMBER OF PAGES IN LENGTH
;35-36 MODULO 0 TO 16383 LENGTH ie file length MOD 16384.
;37 EXECUTE PAGE NUMBER if applicable
;38-39 EXECUTE OFFSET (8000-BFFFH) LSB/MSB if applicable
;40-47 SPARE 8 BYTES (Comment Field
|
|
|
Links
SimCoupe
- Great Sam Coupe Emulator!
Sam.Speccy.cz - Great site with tons of
technical info
** Yes I've called it "Sam Coupe" not "Sam Coup�" - If I don't know
how to type the � symbol no-one searching for it will either!
| |
Buy my Assembly programming book on Amazon in Print or Kindle!
Available worldwide! Search 'ChibiAkumas' on your local Amazon website!
Click here for more info!
Buy my Assembly programming book on Amazon in Print or Kindle!
Available worldwide! Search 'ChibiAkumas' on your local Amazon website!
Click here for more info!
Buy my Assembly programming book on Amazon in Print or Kindle!
Available worldwide! Search 'ChibiAkumas' on your local Amazon website!
Click here for more info!
|