Updated Boot
First I have to update boot.asm, the code to load CP/M into memory. The CP/M V2 only had 32kb of RAM so the CP/M source was located at 0x8000. As CP/M V3 has 56k of RAM so the CP/M source is located at 0xE000.
Here is the boot assembly code (i8085):
; boot.asm: Load CP/M from ROM ; Calc CPM addresses msize equ 56 ; 56k RAM sectors equ 16 ; sectors per track for my system systrks equ 4 ; my boot system has 4 tracks of 16 sectors bias equ (msize-20-1)*1024 ; calculation for my system ccp equ 3400h+bias cstart equ 4a00h+bias org 0e000h ; executed in ROM after shift down jmp 0e003h ; reset bootstrap boot: di ; disable interrupts lxi sp,ccp-0080h ; convenient place lxi d,ccp-0080h ; start of boot dst lxi h,0e000h ; start of ROM (boot src) mvi c,sectors ; sectors per track mvi b,systrks ; sytem track count push b ; save boot$nextsect: mvi b,128 ; sector size boot$copysect: mov a,m inx h stax d inx d dcr b jnz boot$copysect dcr c jnz boot$nextsect pop b dcr b push b jnz boot$nextsect ; Cold boot jmp cstart end
Updated CBIOS
CBIOS has a number of alterations to suit the new hardware design:
; Calc CPM addresses msize equ 56 ; RAM capacity sectors equ 16 ; sectors per track for my system systrks equ 4 ; my boot system has 4 tracks of 16 sectors bias equ (msize-20-1)*1024 ; adjusted for my system cbase equ 3400h+bias ; base of ccp fbase equ cbase+800h ; base of bdos bdos equ cbase+806h ; bdos entry cbios equ cbase+1600h ; base of custom bios (cold boot entry) spbase equ msize*1024 ; sp base (use top of RAM) usrdsk equ 0004h ; current user and disk number iobyte equ 0003h ; intel i/o byte rst7.5 equ 003ch ; interrupt to read serial data input lf equ 0ah ; line feed cr equ 0dh ; carriage return ; Custom CP/M 2.2 BIOS org cbios ; jump vector for individual subroutines jmp cboot ; cold start wstart: jmp wboot ; warm start jmp const ; console status jmp conin ; console character in jmp conout ; console character out jmp list ; list character out jmp punch ; punch character out jmp reader ; reader character out jmp home ; move head to home position jmp seldsk ; select disk jmp settrk ; set track number jmp setsec ; set sector number jmp setdma ; set dma address jmp read ; read disk jmp write ; write disk jmp listst ; return list status jmp sectran ; sector translate ; System uses a two Flash AT29C020-90B with 2048 x 128b pages (256k) ; Set as 128 tracks of 16 sectors of 128 bytes ; System uses tracks 0 to 3 (64 sectors) ; Directory is track 4 and 7 (128 entries) ; Leaving 240kb file storage using 2048b blocks per chip dpbase: ; disk Parameter header for disk A (system) dw trans, 0000h dw 0000h, 0000h dw dirbf, dpblk256s dw chk00, all00 ; disk parameter header for disk B (system) dw trans, 0000h dw 0000h, 0000h dw dirbf, dpblk256s dw chk01, all01; ; disk parameter header for disk C (data) - Not installed dw trans, 0000h dw 0000h, 0000h dw dirbf, dpblk256d dw chk02, all02 ; disk parameter header for disk D (data) - Not installed dw trans, 0000h dw 0000h, 0000h dw dirbf, dpblk256d dw chk03, all03 ; sector translate vector (i.e. no translation) trans: db 1, 2, 3, 4 ; sectors 1, 2, 3, 4 db 5, 6, 7, 8 ; sectors 5, 6, 7, 6 db 9, 10, 11, 12 ; sectors 9, 10, 11, 12 db 13, 14, 15, 16 ; sectors 13, 14, 15, 16 ; disk parameter block for system disk (256k) and 1k block size dpblk256s: dw sectors ; SPT: sectors per track db 3 ; BSH: block shift factor db 7 ; BLM: block mask db 0 ; EXM: extended block mask dw 247 ; DSM: disk blocks - 1 dw 127 ; DRM: directory max - 1 db 240 ; AL0: alloc 0 (=4 bits) db 0 ; AL1: alloc 1 dw 0 ; CKS: check size (= not removable) dw systrks ; OFF: track offset ; disk parameter block for data disk (256k) and 1k block size dpblk256d: dw sectors ; SPT: sectors per track db 3 ; BSH: block shift factor db 7 ; BLM: block mask db 0 ; EXM: extended block mask dw 255 ; DSM: disk blocks - 1 dw 127 ; DRM: directory max - 1 db 240 ; AL0: alloc 0 =(DRM+1)/32, =4 bits, =[11110000]) db 0 ; AL1: alloc 1 (=[00000000]) dw 0 ; CKS: check size (not removable) dw 0 ; OFF: track offset (no system) ; BIOS functions cboot: ; set cold boot defaults only di ; ? make it obvious lxi sp,spbase ; use space at top of RAM for stack xra a ; zero in the accum sta iobyte ; clear the iobyte sta usrdsk ; select user and disk zero mvi c,0 ; select disk 0 call seldsk call home ; Sets Disk and Track 0 ; setup 82C52 SIO: 9600,8N1 on RST7.5 mvi a,05bh ; set SOD low, reset RST7.5 and unmask RST7.5 sim mvi a,03Ch ; 8N1 sta 0041h mvi a,066h ; Use interrupt with DTR/CTS sta 0042h mvi a,02Ah ; Set 9600 buad (using a 5MHz CPU clock) sta 0043h ; display logon message lxi h,signon ; Show cold boot message call prmsg ; print message jmp gocpm ; initialize and go to cp/m wboot: ; reload CP/M but skip boot on sector 1 di ; ? make it obvious lxi sp,spbase ; use space at top of RAM for stack ; setup system disk mvi c,0 ; select disk 0 call seldsk call home ; Sets Disk and Track 0 ; load CP/M lxi d,cbase ; start of boot dst lxi h,0e080h ; start of boot src (start at sector 2) mvi c,sectors ; sectors per track mvi b,systrks ; track count (four system tracks) push b ; save dcr c ; skip sector 1 wboot$nextsect: mvi b,128 ; sector size wboot$copysect: mov a,m inx h stax d inx d dcr b jnz wboot$copysect dcr c jnz wboot$nextsect pop b dcr b push b jnz wboot$nextsect jmp gocpm ; set parameters and go to cp/m gocpm: mvi a,0c3h ; c3h is a jmp instruction sta 0000h ; for jmp to wboot lxi h,wstart ; wboot entry point shld 0001h ; set address field for jmp at 00000h sta 0005h ; for jmp to bdos lxi h,bdos ; bdos entry point shld 0006h ; address field of Jump at 0005h to bdos sta rst7.5 ; for jmp to getchar lxi h,getchar ; get serial data input entry point shld rst7.5+1 ; set address field of ISR to get serial char lxi b,80h ; default dma address is 80h call setdma mvi a,4 ; define four drives sta drives dcr a ; test if usrdsk>=drives mov c,a lda usrdsk ; get current user and disk number cmp c jc gocpm$end mvi a,00h gocpm$end: sta usrdsk mov c,a ; send to the ccp ei ; enable the interrupt system jmp cbase ; go to cp/m ; get serial character and put in the ring buffer (called by RST7.5) ; assume a 10 MHz crystal: baud=9600,8N1 getchar: di ; no interrupts push psw push b push d push h lda 40h ; Read 82C52 register ; Save in ring buffer getchar$5: lda rput ; rbuf put ptr (0-f) mov e,a lxi h,rbuf mvi d,00h dad d inr a ani 0fh sta rput mov m,c pop h pop d pop b pop psw ei ret signon: ; signon message db cr,lf,lf db 'my CP/M 2.2 V3' db cr,lf,0 ; print zero delimited string pointed to by prmsg: mov a,m ora a rz ; exit on zero ; more to print push h mov c,a call putchar pop h inx h jmp prmsg ; console status, return 0ffh if character ready, 00h if not const: lda rput mov c,a lda rget sub c rz mvi a,0ffh ret ; get console character into A (blocking) conin: lda rget mov c,a lda rput sub c jz conin ; wait for a character lxi h,rbuf mvi b,00h dad b mov a,c inr a ani 0fh sta rget mov a,m ani 7fh mov c,a ret ; put character to serial out from register C ; assumes a 10 MHz crystal: baud=9600,8,N,1 putchar: push psw mov a,c sta 0040h pop psw ret conout: di ; Acccept no serial in while serial out call putchar ; ? putchar does not alter interrupts ei ret ; list character from register c list: ret ; null subroutine ; return list status (0 if not ready, 1 if ready) listst: xra a ; 0 is always ok to return ret ; punch character from register C punch: ret ; null subroutine ; reader character into register a from reader device reader: mvi a,1ah ; enter end of file for now (replace later) ani 7fh ; remember to strip parity bit ret ; move to the track 0 position of current drive home: ; translate this call into a settrk call with parameter 0 mvi c,0 ; select track 0 mvi b,0 call settrk ret ; we will move to 00 on first read/write ; select disk given by register c seldsk: lxi h,0000h ; error return code lda drives cmp c rc ; out of range rz ; out of range mov a,c sta diskno ; select disk selected but page is reset! rlc ; provision for four disks rlc ani 0c0h ; resets page to 0 out 0ffh ; output to disk/page register ; compute Disk Parameter Header address lda diskno mov l, a ; l=disk number 0, 1, 2, 3 mvi h, 0 ; high order zero dad h dad h dad h dad h lxi d,dpbase dad d ; hl=dpbase+diskno*16 ret ; settrk: ; set track given by registers mov h,b mov l,c shld track ret ; setsec: ; set sector given by register c mov a, c sta sector ret ; translate the sector using the translate table [de] sectran: xchg ; set hl=translation table dad b ; set hl=hl+sector mov l,m ; get translated sector mvi h,0 ; ? sector numbers between 1 and 255 ret ; return with translated sector in setdma: ; set dma address given by registers mov h,b ; high order address mov l,c ; low order address shld dmaad ; save the address ret ; calculate disk number, disk page, track and sector address ; returns = DDTT TTTT 111T TSSS S000 0000 calcdskadr: ; set disk number (0-3) lda diskno ; load diskno number rrc rrc ani 0c0h mov c,a ; DD00 0000 ; set low byte of track number lda track ; load low byte of track number rrc rrc ani 03fh ora c ; DDTT TTTT mov c,a ; save ; set low nibble of sector number lda sector ; load sector number dcr a ; less one for memory address stc rar mov d,a ; 1SSS SSSS mvi a,00h rar ; S000 0000 mov e,a ; save mvi a,0e7h ora d ; 1110 0SSS ; set low nibble of low byte of track number lda track ; load low byte of track number rlc rlc rlc ani 18h ora d ; 111T TSSS mov d,a ; save ret ; read sector from disk read: lhld dmaad ; set DMA address call calcdskadr ; calculate disk address mov a,c ; out (set) disk number and page out 0ffh mvi b,80h ; sector size read$1: ldax d inx d mov m,a inx h dcr b jnz read$1 xra a ; always succeeds ret ; write sector from disk write: call calcdskadr ; calculate disk address lhld dmaad ; set DMA address mov a,c ; out (set) disk number and page out 0ffh mvi b,80h ; sector size xchg ; swap destination and source di ; ? timing critial write$page: ; write page (128b) ldax d inx d mov m,a inx h dcr b jnz write$page push psw ; reset rst7.5 mvi a,010h sim pop psw ei ; wait for flash dcx h write$wait: cmp m jnz write$wait inx h xra a ; always succeeds ret ; BIOS data area drives: ds 1 ; number of disk drives 1-16 max diskno: ds 1 ; disk number 0-15 max track: ds 2 ; track number 0-65535 max sector: ds 1 ; sector number 1-255 max dmaad: ds 2 ; direct memory address ; scratch ram area for bdos use dirbf: ds 128 ; scratch directory area all00: ds 31 ; allocation vector 0 (=DSM/8+1) all01: ds 31 ; allocation vector 1 (=DSM/8+1) all02: ds 32 ; allocation vector 2 (=DSM/8+1) all03: ds 32 ; allocation vector 3 (=DSM/8+1) chk00: ds 16 ; check vector 0 (CKS=0, therefore not used) chk01: ds 16 ; check vector 1 (CKS=0, therefore not used) chk02: ds 16 ; check vector 2 (CKS=0, therefore not used) chk03: ds 16 ; check vector 3 (CKS=0, therefore not used) ; Serial use: rbuf: ds 16 ; ring buffer for serial data rget: db 0 ; ring buffer get pointer rput: db 0 ; ring buffer put pointer bitcnt: db 33 ; bit count for 9600 baud and 10MHz crystal end
I willdouble check the code tomorrow before uploading the code to the system disk (e.i. W29C020).
Reblocking
Once I get the W29C020 working I need to code the reblocking for the W29C040 as it has a 256b page size (rather than 128b as per the W29C020).
MyCP/M EMU
I rebuilt my EMU for the new hardware. Updated the Intel HEX import of HEX16 files. Picked up a number of errors with CBIOS. On the EMU it now displays the bootup message.
Some problems with reading the console which seems to be an EMU error. The interrupt is working but there seems to be a memory conflict somewhere.
I am tempted to program the Flash chip and try my luck. No luck.
I have been working a few hours every few days on this and I have tracked down the problem to a jump into the "read" cbios routine. Still difficult to work out where the jump came from. Basically, you can trace the code but finding the error in millions of instructions is difficult. Still working on it.
TBC...
AlanX
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.