aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2014-06-01 15:09:53 -0700
committerH. Peter Anvin <hpa@zytor.com>2014-06-01 15:09:53 -0700
commit78c734aef743b43c87c82eacbee3e0d2d2c9555f (patch)
treea65f7969a6ce9bf7740dfe5c3ef17a0f0f8b0a7f
parent81f02dd08a3879cce12754d8f4ec1b260bd210a5 (diff)
downloadabc80-78c734aef743b43c87c82eacbee3e0d2d2c9555f.tar.gz
abc80-78c734aef743b43c87c82eacbee3e0d2d2c9555f.tar.xz
abc80-78c734aef743b43c87c82eacbee3e0d2d2c9555f.zip
Actually working version of CP/M
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--data/cbios.asm183
-rw-r--r--data/cpm.asm13
-rw-r--r--data/cpm22.asm5
3 files changed, 92 insertions, 109 deletions
diff --git a/data/cbios.asm b/data/cbios.asm
index caaa382..77746ae 100644
--- a/data/cbios.asm
+++ b/data/cbios.asm
@@ -1,15 +1,15 @@
; SOCZ80 CP/M 2.2 BIOS (or at least an attempt!)
; 2013-11-03 Will Sowerbutts
-
+; 2014-06-01 H. Peter Anvin
+;
; useful resources:
; http://www.cpm.z80.de/manuals/cpm22-m.pdf
; http://www.retrotechnology.com/dri/howto_cpm.html#myown
; http://www.retrotechnology.com/dri/cpm_features.html
; cpmtools package
-msize: equ 64 ; KB of system RAM
-biosextra: equ 512
-bias: equ (msize-20)*1024-biosextra
+msize: equ 63 ; KB of system RAM
+bias: equ (msize-20)*1024
ccp: equ 0x3400+bias
bdos: equ ccp+0x0806
bios: equ ccp+0x1600
@@ -46,68 +46,37 @@ wboote: jp wboot ; warm start
kbdvec: defw irq_kbd
v24vec: defw irq_v24
-; disk parameter header (16 bytes for each drive), see page 6-28 in CP/M 2.2 operating system manual
+; disk parameter header (16 bytes for each drive),
+; the chk and alv get dynamically adjusted
dpbase:
- ; disk 0 (A)
- dw 0 ; sector translation table (0 = no translation)
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw dirbf ; DIRBUF (address of shared 128 byte scratch pad area)
- dw dpblk ; DPB (disk parameter block)
- dw chk00 ; CSV (unique scratch pad used to check for changed disks)
- dw alv00 ; ALV (unique scratch pad for allocation information)
- ; end of disk 0
-
- ; disk 1 (B)
- dw 0 ; sector translation table (0 = no translation)
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw dirbf ; DIRBUF (address of shared 128 byte scratch pad area)
- dw dpblk ; DPB (disk parameter block)
- dw chk01 ; CSV (unique scratch pad used to check for changed disks)
- dw alv01 ; ALV (unique scratch pad for allocation information)
- ; end of disk 1
-
- ; disk 2 (C)
- dw 0 ; sector translation table (0 = no translation)
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw dirbf ; DIRBUF (address of shared 128 byte scratch pad area)
- dw dpblk ; DPB (disk parameter block)
- dw chk02 ; CSV (unique scratch pad used to check for changed disks)
- dw alv02 ; ALV (unique scratch pad for allocation information)
- ; end of disk 2
-
- ; disk 3 (D)
- dw 0 ; sector translation table (0 = no translation)
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw 0 ; must be 0
- dw dirbf ; DIRBUF (address of shared 128 byte scratch pad area)
- dw dpblk ; DPB (disk parameter block)
- dw chk03 ; CSV (unique scratch pad used to check for changed disks)
- dw alv03 ; ALV (unique scratch pad for allocation information)
- ; end of disk 3
-
-ndisks: equ 4 ; number of disks we defined
+ dw 0 ; sector translation table (0 = no translation)
+ dw 0 ; must be 0
+ dw 0 ; must be 0
+ dw 0 ; must be 0
+ dw dirbf ; DIRBUF (address of shared 128 byte scratch pad area)
+ dw dpblk ; DPB (disk parameter block)
+dp_csv: dw csv ; CSV (unique scratch pad used to check for changed disks)
+dp_alv: dw alv ; ALV (unique scratch pad for allocation information)
+
+ndisks: equ 8 ; number of disks we defined
; disk parameter block (can be shared by all disks with same configuration)
-; each volue is 15,597,568 bytes (238*256*256). We represent this as
+; each volue is 15,597,568 bytes (238*256*256), which is too much for
+; CP/M 2.2 to handle, so split each into two subvolumes. We represent this as
; tracks of 8192 bytes (64 sectors x 128 bytes) which matches an UFD-DOS
-; "cluster". This means there are 1904 tracks. The first track is reserved
-; for the system, leaving 1903*64 = 121792 user sectors.
-; We use 8K blocks, matching ABC clusters, so there are 1903 user blocks.
+; "cluster". This means there are 952 tracks per subvolume.
+; The first track is reserved for the system, leaving
+; 951*64 = 60864 user sectors. We use 8K blocks, matching ABC clusters,
+; so there are 951 user blocks. A smaller block size eats up too much
+; memory in the alv tables.
dpblk:
dw 64 ; SPT: number of 128 byte sectors per track
db 6 ; BSH: block shift factor (see manual for table)
db 63 ; BLM: block mask (see manual for table)
db 3 ; EXM: extent mask (see manual for table, using entries marked N/A turns out to be a bad idea!)
- dw 1903 ; DSM: (disk bytes / block bytes) - 1, change alv0x etc if you change this; this is the number of the last sector on the disk, excluding system tracks (ie more system tracks -> this gets smaller)
- dw 1023 ; DRM: directory max entries - 1
- db 0xf0 ; AL0: directory sector allocation bitmask byte 0
+ dw 950 ; DSM: (disk bytes / block bytes) - 1, change alv0x etc if you change this; this is the number of the last sector on the disk, excluding system tracks (ie more system tracks -> this gets smaller)
+ dw 511 ; DRM: directory max entries - 1
+ db 0xc0 ; AL0: directory sector allocation bitmask byte 0
db 0x00 ; AL1: directory sector allocation bitmask byte 1
dw 0 ; CKS: check size (change chk0x etc if you change this)
dw 1 ; OFF: track offset (number of system tracks)
@@ -153,12 +122,16 @@ boot: ; Cold boot
out (7),a ; Map 3, NMI disabled
ld sp,0x100 ; Put our stack in the default DMA buffer
- ; Zero all memory (just in case)
- ld hl,0
- ld de,1
- ld bc,bios-1
- ld (hl),l
+ ; Zero all memory (just in case). This intentionally
+ ; wraps around the end of memory.
+ ld ix,(currow)
+ xor a
+ ld hl,zero
+ ld de,zero+1
+ ld bc,bios-zero-1
+ ld (hl),a
ldir
+ ld (currow),ix
; say hello
ld hl,bootmsg
@@ -293,6 +266,7 @@ conout: ; write chracter from C to console
jr z,con_cr
; Fall through
con_print:
+ and 07Fh
call con_getaddr
di
ld a,4 ; Map 0, NMI off
@@ -443,17 +417,24 @@ seldsk: ; select disk indicated by register C
ld a, c
cp ndisks
ret nc ; return (with error code) if C >= ndisks ie illegal drive
- ld (curdisk), a ; store current disk
+ or 24h*2 ; +4 for volume, CP/M mode, C flag <- 0
+ rra
+ ld (curdisk), a ; store current ABC volume number + CP/M flag
+ ld a,h ; H = 0!
+ jr nc,sd1
+ ld a,119
+sd1: ld (curxtrk), a ; store track offset (+119 for odd volume)
; compute proper disk parameter header address in HL
- add a,a ; *2
- add a,a ; *4
- add a,a ; *8
- add a,a ; *16
- add a,dpbase & 0xff
- ld l,a
- ld h,dpbase/256
- ; HL = dpbase + disk number * 16
- ret
+
+ ; Each allocation vector is 120 bytes long
+ ld a,120
+ ld e,c
+ ld d,h ; = 0
+ ld hl,alv
+ call multiply_add
+ ld (dp_alv),hl
+ ld hl,dpbase
+ ret
home: ld bc, 0
; fall through into seltrk
@@ -477,24 +458,26 @@ setdma: ; set DMA address given by BC
ret
read: ; read a sector from disk
- ; XXX: add error handing!
+ ; XXX: add error handing before trying to read back data
ld c,03h ; READ + SECTOR TO HOST
call sendcmd
ld hl,(curdmaaddr)
ld bc,128*256+0
inir
- xor a ; Success!
+end_op:
+ in a,(1)
+ rrca
+ jr nc,end_op
+ in a,(0) ; 0 = OK
ret
write: ; write sector to disk
- ; XXX: add error handing!
ld c,0Ch ; SECTOR FROM HOST + WRITE
call sendcmd
ld hl,(curdmaaddr)
ld bc,128*256+0
otir
- xor a ; Success!
- ret
+ jr end_op
; Send a controller command, C = K0 command byte
; Clobbers A DE HL, returns with disk selected
@@ -503,8 +486,7 @@ sendcmd:
out (1),a ; Select disk
out (2),a ; Start command
- ld a,(curdisk) ; curdisk
- or 24h ; +4 for volume, CP/M mode
+ ld a,(curdisk) ; curdisk + 24h
ld e,a
ld a,(cursector)
srl a
@@ -524,6 +506,9 @@ bc1:
rr d
or d
ld h,a
+ ld a,(curxtrk)
+ add a,l
+ ld l,a
; Now: K0 = C, K1 = E, K2 = L, K3 = H
sc_wait1:
@@ -547,26 +532,34 @@ sc_wait_ok:
ret c
jr sc_wait_ok
-bootmsg: db "CP/M BIOS (H. Peter Anvin, 2014-05-09)\r\n"
+multiply_add: ; HL <- HL + DE * A, trashes B
+ ld b,8
+m1:
+ rrca
+ jr nc,m2
+ add hl,de
+m2:
+ sla e
+ rl d
+ djnz m1
+ ret
+
+bootmsg: db "CP/M BIOS (H. Peter Anvin, 2014-06-01)\r\n"
db "CP/M 2.2 Copyright 1979 (c) by Digital Research\r\n"
+zero:
db 0
-;---------------------------------------------------------------------------------------------------------------
+; ----------------------------------------------------------------------------
-; scratch RAM used by BIOS
-curdisk: db 0
-cursector: db 0
-curtrack: dw 0
-curdmaaddr: dw 0
-conflag: db 0
+; scratch RAM (BSS) used by BIOS
+curdisk: db 0
+curxtrk: db 0
+cursector: db 0
+curtrack: dw 0
+curdmaaddr: dw 0
+conflag: db 0
; scratch RAM used by BDOS
dirbf: ds 128 ; directory scratch area
-alv00: ds 239 ; allocation vector for disk 0, must be (DSM/8)+1 byte
-alv01: ds 239 ; allocation vector for disk 1, must be (DSM/8)+1 bytes
-alv02: ds 239 ; allocation vector for disk 2, must be (DSM/8)+1 bytes
-alv03: ds 239 ; allocation vector for disk 3, must be (DSM/8)+1 bytes
-chk00: ds 0 ; check vector for disk 0 (must be CKS bytes long)
-chk01: ds 0 ; check vector for disk 1 (must be CKS bytes long)
-chk02: ds 0 ; check vector for disk 2 (must be CKS bytes long)
-chk03: ds 0 ; check vector for disk 3 (must be CKS bytes long)
+alv: ds 120*ndisks ; allocation vectors, each (DSM/8)+1 byte
+csv: ds 0*ndisks ; check vectors, each CKS bytes
diff --git a/data/cpm.asm b/data/cpm.asm
index 061a3c3..0e7bdbd 100644
--- a/data/cpm.asm
+++ b/data/cpm.asm
@@ -14,8 +14,8 @@
; CP/M loader for ABC80-DE1
;
HDSEL: equ 36
-RAMSIZE: equ 64
-BIAS: equ (64-20)*1024-512
+RAMSIZE: equ 63
+BIAS: equ (RAMSIZE-20)*1024
CPMBIOS: equ BIAS+4A00h
ABCCURSOR: equ 65011
CPMCURSOR: equ 0FFFEh
@@ -36,15 +36,6 @@ _start:
ld bc,bios_size
ldir
- ; Zero memory above the BIOS
- ld l,e
- ld h,d
- inc de
- ld bc,CPMCURSOR-(CPMBIOS+bios_size)-1
- xor a
- ld (hl),a
- ldir
-
jp CPMBIOS
bios:
diff --git a/data/cpm22.asm b/data/cpm22.asm
index 039dc59..90b6c96 100644
--- a/data/cpm22.asm
+++ b/data/cpm22.asm
@@ -11,8 +11,7 @@
; Set memory limit here. This is the amount of contigeous
; ram starting from 0000. CP/M will reside at the end of this space.
;
-MEM: EQU 64 ;for a 64k system (TS802 TEST - WORKS OK).
-XBIOS: EQU 512 ;extra space for BIOS
+MEM: EQU 63 ;for a 64k system (TS802 TEST - WORKS OK).
;
IOBYTE: EQU 3 ;i/o definition byte.
TDRIVE: EQU 4 ;current drive name and user number.
@@ -40,7 +39,7 @@ DEL: EQU 7FH ;rubout
;
; Set origin for CP/M
;
- ORG (MEM-7)*1024-XBIOS
+ ORG (MEM-7)*1024
;
CBASE: JP COMMAND ;execute command processor (ccp).
JP CLEARBUF ;entry to empty input buffer before starting ccp.