Guest User

CP/M 3 BIOS for Bondwell 14

a guest
Oct 25th, 2021
266
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.30 KB | None | 0 0
  1. ;
  2. ; CP/M 3 BIOS for Bondwell 14
  3. ;
  4. ;
  5. ; Assemble with a relocating assembler to produce BIOS3.REL, then use
  6. ; the DRI linker LINK.COM to produce BNKBIOS3.SPR
  7. ;
  8. ; link bnkbios3[b]=bios3
  9. ;
  10. ; To create CPM3.SYS run GENCPM using all defaults when prompted
  11. ; except for the following -
  12. ;
  13. ; number of console lines #25
  14. ; top page of memory f7
  15. ; common memory base page 80
  16. ; number of memory segments 2
  17. ; memory segment 0 (00,50,00)
  18. ; memory segment 1 (10,70,02)
  19. ;
  20. ; The first 4k bytes of bank 2 is reserved, the space being used to
  21. ; hold a copy of CCP.COM for quick warm starts.
  22. ;
  23.  
  24. day equ 30
  25. mon equ 12
  26. year equ 94
  27.  
  28. .z80 ; required for M80 assembler
  29.  
  30. no equ 0
  31. yes equ not no
  32.  
  33. errors equ no ; display BIOS error message
  34. lcase equ yes ; if caps-lock, change upper to lower
  35. minbios equ no ; minimum size BIOS
  36.  
  37. maxtry equ 10 ; number re-tries on disk-error
  38.  
  39. ; disk definitions
  40.  
  41. bw12 defl yes ; Bondwell 12
  42. sv3 defl yes ; Spectravideo 318/328
  43. kay2 defl yes ; Kaypro II
  44. osb1 defl yes ; Osborne 1
  45. amp4 defl yes ; Ampro 48 tpi DS
  46. kay4 defl yes ; Kaypro 4/10
  47.  
  48. if minbios ; remove unwanted disk definitions
  49. bw12 defl no
  50. sv3 defl no
  51. kay2 defl no
  52. osb1 defl no
  53. amp4 defl no
  54. kay4 defl no
  55. endif
  56.  
  57. bell equ 7
  58. lf equ 10
  59. cr equ 13
  60.  
  61. ccp equ 100h
  62. screen equ 0f800h ; screen ram
  63. cols equ 80 ; # screen columns
  64. rows equ 25 ; # screen rows
  65.  
  66. ; system control block
  67.  
  68. extrn @civec,@covec ; console input/output vectors
  69. extrn @aivec,@aovec ; auxiliary input/output vectors
  70. extrn @lovec ; list output vector
  71. extrn @mxtpa ; top of tpa (address 6,7)
  72.  
  73. ; ports
  74.  
  75. crtcr equ 10h ; 6845 CRTC control reg
  76. crtdr equ crtcr+1 ; data reg
  77.  
  78. fdcst equ 20h ; 765 FDC status reg
  79. fdcdr equ fdcst+1 ; data reg
  80.  
  81. pddra equ 3ch ; 6821 PIA DDR port A
  82. pcra equ pddra+1 ; control reg A
  83. pddrb equ pcra+1 ; DDR port A
  84. pcrb equ pddrb+1 ; control reg A
  85.  
  86. siodra equ 40h ; Z80 SIO/0
  87. siocra equ siodra+1 ;
  88. siodrb equ siocra+1 ;
  89. siocrb equ siodrb+1 ;
  90.  
  91. audio equ 50h ; MC1408 8-bit D-A
  92.  
  93. timer0 equ 60h ; 8253 timer 0
  94. timer1 equ timer0+1 ; timer 1
  95. timer2 equ timer1+1 ; timer 2
  96. timercr equ timer2+1 ; control reg
  97.  
  98. ; BIOS jump table
  99.  
  100. ?boot: jp boot ; 0
  101. ?wboot: jp wboot ; 1
  102. jp const ; 2
  103. jp conin ; 3
  104. ?cono: jp conout ; 4
  105. jp list ; 5
  106. jp auxout ; 6
  107. jp auxin ; 7
  108. jp home ; 8
  109. jp seldsk ; 9
  110. jp settrk ; 10
  111. jp setsec ; 11
  112. jp setdma ; 12
  113. jp read ; 13
  114. jp write ; 14
  115. jp listst ; 15
  116. jp sectrn ; 16
  117.  
  118. ; CP/M3 BIOS calls
  119.  
  120. jp conost ; 17 conout status
  121. jp auxist ; 18 aux in status
  122. jp auxost ; 19 aux out status
  123. jp devtbl ; 20 addr of device definition table
  124. jp ?cinit ; 21 change baud rate of device
  125. jp getdrv ; 22 addr of disk drive table
  126. jp multio ; 23 set multiple record count
  127. jp flush ; 24 flush disk caching
  128. jp ?move ; 25 block move
  129. jp ?time ; 26 time/date
  130. ?bnksel:
  131. jp bnksel ; 27 select bank for code execution
  132. jp setbnk ; 28 select different bank for i/o
  133. jp ?xmove ; 29 set source/destination banks
  134.  
  135. ; user specified calls
  136.  
  137. jp ?fnkeys ; 30 returns addr of function key table
  138. jp 0000 ; 31 spare
  139. jp 0000 ; 32 spare
  140.  
  141. boot: di ; disable interrupts
  142. ld sp,boot$stack
  143. ld c,15 ; initialise all 16 character devices
  144. c$init$loop:
  145. push bc
  146. call ?cinit
  147. pop bc
  148. dec c
  149. jp p,c$init$loop
  150.  
  151. call ?init ; additional system initialisation
  152. ; and sign-on message
  153. ld bc,16*256+0
  154. ld hl,@dtbl
  155. d$init$loop:
  156. push bc
  157. ld e,(hl)
  158. inc hl
  159. ld d,(hl)
  160. inc hl
  161. ld a,e
  162. or d
  163. jr z,d$init$next
  164. push hl
  165. ex de,hl
  166. dec hl
  167. dec hl
  168. ld a,(hl)
  169. ld (@rdrv),a
  170. ld a,c
  171. ld (@adrv),a
  172. dec hl
  173. ld d,(hl)
  174. dec hl
  175. ld e,(hl)
  176. ex de,hl
  177. call ipchl
  178. pop hl
  179. d$init$next:
  180. pop bc
  181. inc c
  182. dec b
  183. jr nz,d$init$loop
  184. jr boot$1
  185.  
  186. boot$1: call set$jumps
  187. call ?ldccp
  188.  
  189. ld hl,cboot ; set BIOS cold start vector
  190. ld (?boot+1),hl
  191. ld hl,auto-1 ; auto-execute string
  192. ld (nxtchr),hl
  193. ld a,16
  194. ld (ccount),a
  195. ei ; enable interrupts
  196. jp ccp ; enter CP/M
  197.  
  198. auto: db 'AUTORUN',cr
  199. db 0
  200.  
  201. cboot: di
  202. in a,(00h) ; cold boot from Rom
  203. in a,(02h)
  204. jp 0000h
  205.  
  206. wboot: di
  207. ld sp,boot$stack
  208. call set$jumps ; set zero page jumps
  209. call ?rlccp ; load first time CCP
  210. ei ; enable interrupts
  211. jp ccp ; enter CP/M
  212.  
  213. set$jumps:
  214. ld a,1
  215. call ?bnksel
  216. ld a,0c3h ; set up jumps
  217. ld (0000),a
  218. ld (0005),a
  219. ld hl,?wboot ; BIOS warm start vector
  220. ld (0001),hl
  221. ld hl,(@mxtpa) ; BDOS vector
  222. ld (0006),hl
  223. ret
  224.  
  225. ds 64 ; stack space
  226.  
  227. boot$stack equ $
  228.  
  229. devtbl: ld hl,@ctbl
  230. ret
  231.  
  232. getdrv: ld hl,@dtbl
  233. ret
  234. ;
  235. ; Output to logical devices - conout, auxout, lst
  236. ;
  237. conout: ld hl,(@covec)
  238. jr out$scan
  239.  
  240. auxout: ld hl,(@aovec)
  241. jr out$scan
  242.  
  243. list: ld hl,(@lovec)
  244. out$scan:
  245. ld b,0
  246. co$next:
  247. add hl,hl
  248. jr nc,not$out$device
  249. push hl
  250. push bc
  251. not$out$ready:
  252. call coster
  253. or a
  254. jr z,not$out$ready
  255. pop bc
  256. push bc
  257. call ?co
  258. pop bc
  259. pop hl
  260. not$out$device:
  261. inc b
  262. ld a,h
  263. or l
  264. jr nz,co$next
  265. ret
  266. ;
  267. ; Get output status of logical device - conout, auxout, lst
  268. ;
  269. conost: ld hl,(@covec)
  270. jr ost$scan
  271.  
  272. auxost: ld hl,(@aovec)
  273. jr ost$scan
  274.  
  275. listst: ld hl,(@lovec)
  276. ost$scan:
  277. ld b,0
  278. cos$next:
  279. add hl,hl
  280. push hl
  281. push bc
  282. ld a,0ffh
  283. call c,coster
  284. pop bc
  285. pop hl
  286. or a
  287. ret z
  288. inc b
  289. ld a,h
  290. or l
  291. jr nz,cos$next
  292. or 0ffh
  293. ret
  294.  
  295. ; check for output device ready, including xon/xoff
  296.  
  297. coster: ld l,b
  298. ld h,0
  299. push hl
  300. add hl,hl ; *8 (8 bytes per physical device)
  301. add hl,hl
  302. add hl,hl
  303. ld de,@ctbl+6 ; get byte
  304. add hl,de
  305. ld a,(hl)
  306. and mbx ; xon/xoff
  307. pop hl
  308. jp z,?cost
  309. ld de,xofflist
  310. add hl,de
  311. call cist1
  312. ld a,(hl)
  313. call nz,ci1
  314. cp 17 ; ctl-q
  315. jr nz,not$q
  316. ld a,0ffh
  317. not$q: cp 19 ; ctl-s
  318. jr nz,not$s
  319. ld a,0
  320. not$s: ld (hl),a
  321. call cost1
  322. and (hl)
  323. ret
  324.  
  325. xofflist:
  326. db -1,-1,-1,-1,-1,-1,-1,-1
  327. db -1,-1,-1,-1,-1,-1,-1,-1
  328.  
  329. cist1: push bc ; get input status, save BC and HL
  330. push hl
  331. call ?cist
  332. pop hl
  333. pop bc
  334. or a
  335. ret
  336.  
  337. cost1: push bc ; get output status, save BC and HL
  338. push hl
  339. call ?cost
  340. pop hl
  341. pop bc
  342. or a
  343. ret
  344.  
  345. ci1: push bc ; get input, save BC and HL
  346. push hl
  347. call ?ci
  348. pop hl
  349. pop bc
  350. ret
  351. ;
  352. ; Get status of logical input device - conin, auxin
  353. ;
  354. const: ld hl,(@civec)
  355. jr ist$scan
  356.  
  357. auxist: ld hl,(@aivec)
  358. ist$scan:
  359. ld b,0
  360. cis$next:
  361. xor a
  362. add hl,hl
  363. call c,cist1
  364. or a
  365. ret nz
  366. inc b
  367. ld a,h
  368. or l
  369. jr nz,cis$next
  370. xor a
  371. ret
  372. ;
  373. ; Input character from logical device - conin, auxin
  374. ;
  375. conin: ld hl,(@civec)
  376. jr in$scan
  377.  
  378. auxin: ld hl,(@aivec)
  379. in$scan:
  380. push hl
  381. ld b,0
  382. ci$next:
  383. xor a
  384. add hl,hl
  385. call c,cist1
  386. or a
  387. jr nz,ci$rdy
  388. inc b
  389. ld a,h
  390. or l
  391. jr nz,ci$next
  392. pop hl
  393. jr in$scan
  394.  
  395. ci$rdy: pop hl
  396. jp ?ci
  397.  
  398. ; vectored calls
  399.  
  400. ipchl: jp (hl)
  401.  
  402. ; print message at (hl) until null byte, save BC and DE
  403.  
  404. ?pmsg: push bc
  405. push de
  406. pmsg$loop:
  407. ld a,(hl)
  408. or a
  409. jr z,pmsg$exit
  410. ld c,a
  411. push hl
  412. call ?cono
  413. pop hl
  414. inc hl
  415. jr pmsg$loop
  416. pmsg$exit:
  417. pop de
  418. pop bc
  419. ret
  420.  
  421. ; report disk error - drive, track, sector
  422.  
  423. if errors
  424. ?pderr: ld hl,drv$msg
  425. call ?pmsg
  426. ld a,(@adrv)
  427. add a,'A'
  428. ld c,a
  429. call ?cono
  430. ld hl,trk$msg
  431. call ?pmsg
  432. ld hl,(@trk)
  433. call ?pdec
  434. ld hl,sec$msg
  435. call ?pmsg
  436. ld hl,(@sect)
  437. call ?pdec
  438. ret
  439.  
  440. drv$msg:
  441. db cr,lf,bell
  442. db 'BIOS ERROR ON '
  443. db 0
  444. trk$msg:
  445. db ': T-'
  446. db 0
  447. sec$msg:
  448. db ', S-'
  449. db 0
  450. endif
  451.  
  452. ; print binary number (hl)
  453.  
  454. if errors
  455. ?pdec: ld bc,table10
  456. ld de,-10000
  457. next: ld a,'0'-1
  458. pdecl: push hl
  459. inc a
  460. add hl,de
  461. jr nc,stoploop
  462. inc sp
  463. inc sp
  464. jr pdecl
  465. stoploop:
  466. push de
  467. push bc
  468. ld c,a
  469. call ?cono
  470. pop bc
  471. pop de
  472. pop hl
  473. ld a,(bc)
  474. ld e,a
  475. inc bc
  476. ld a,(bc)
  477. ld d,a
  478. inc bc
  479. ld a,e
  480. or d
  481. jr nz,next
  482. ret
  483.  
  484. table10:
  485. dw -1000,-100,-10,-1,0
  486. endif
  487.  
  488. ; select bank for code execution and default dma
  489.  
  490. bnksel: ld (@cbnk),a
  491. jp ?bank
  492.  
  493. ; select disk drive (c), return disk parameter header (hl)
  494.  
  495. seldsk: ld a,c
  496. ld (@adrv),a
  497. ld l,c
  498. ld h,0
  499. add hl,hl
  500. ld bc,@dtbl
  501. add hl,bc
  502. ld a,(hl)
  503. inc hl
  504. ld h,(hl)
  505. ld l,a
  506. or h
  507. ret z
  508. ld a,e
  509. and l
  510. jr nz,not$first$select
  511. push hl
  512. ex de,hl
  513. ld hl,-2
  514. add hl,de
  515. ld a,(hl)
  516. ld (@rdrv),a
  517. ld hl,-6
  518. add hl,de
  519. ld a,(hl)
  520. inc hl
  521. ld h,(hl)
  522. ld l,a
  523. call ipchl
  524. pop hl
  525. not$first$select:
  526. ret
  527.  
  528. ; set disk to logical home
  529.  
  530. home: ld bc,0000
  531.  
  532. ; set disk track
  533.  
  534. settrk: ld l,c
  535. ld h,b
  536. ld (@trk),hl
  537. ret
  538.  
  539. ; Set disk sector
  540.  
  541. setsec: ld l,c
  542. ld h,b
  543. ld (@sect),hl
  544. ret
  545.  
  546. ; Set disk I/O memory address
  547.  
  548. setdma: ld l,c
  549. ld h,b
  550. ld (@dma),hl
  551. ld a,(@cbnk)
  552.  
  553. ; Select different bank for disk I/O DMA operations
  554.  
  555. setbnk: ld (@dbnk),a
  556. ret
  557.  
  558. ; Translate sequential to physical sector
  559.  
  560. sectrn: ld l,c
  561. ld h,b
  562. ld a,d
  563. or e
  564. ret z
  565. ex de,hl
  566. add hl,bc
  567. ld l,(hl)
  568. ld h,0
  569. ret
  570.  
  571. ; Read physical sector
  572.  
  573. read: ld hl,(@adrv)
  574. ld h,0
  575. add hl,hl
  576. ld de,@dtbl
  577. add hl,de
  578. ld a,(hl)
  579. inc hl
  580. ld h,(hl)
  581. ld l,a
  582. push hl
  583. ld de,-8
  584. add hl,de
  585. jr rw$common
  586.  
  587. ; Write physical sector
  588.  
  589. write: ld hl,(@adrv)
  590. ld h,0
  591. add hl,hl
  592. ld de,@dtbl
  593. add hl,de
  594. ld a,(hl)
  595. inc hl
  596. ld h,(hl)
  597. ld l,a
  598. push hl
  599. ld de,-10
  600. add hl,de
  601.  
  602. rw$common:
  603. ld a,(hl)
  604. inc hl
  605. ld h,(hl)
  606. ld l,a
  607. pop de
  608. dec de
  609. dec de
  610. ld a,(de)
  611. ld (@rdrv),a
  612. inc de
  613. inc de
  614. jp (hl)
  615.  
  616. ; Set multiple record count for disk i/o
  617.  
  618. multio: ld (@cnt),a
  619. ret
  620.  
  621. ; Flush BIOS maintained disk cache
  622.  
  623. flush: xor a
  624. ret
  625.  
  626. @adrv: db 0 ; currently selected drive
  627. @rdrv: db 0 ; controller relative drive
  628. @trk: dw 0 ; current logical track
  629. @sect: dw 0 ; current logical sector
  630. @dma: dw 0 ; current dma address
  631. @cnt: db 0 ; record count for multisector transfer
  632. @dbnk: db 0 ; bank for dma operations
  633. @cbnk: db 0 ; bank for processor operations
  634.  
  635. ; additional initialisation, sign-on message
  636.  
  637. ?init: ld hl,8000h
  638. ld (@civec),hl
  639. ld (@covec),hl
  640.  
  641. ld hl,4000h
  642. ld (@lovec),hl
  643.  
  644. ld hl,2000h
  645. ld (@aivec),hl
  646. ld (@aovec),hl
  647.  
  648. ld hl,signon
  649. call ?pmsg
  650. ret
  651.  
  652. ; Get ccp for first time
  653.  
  654. ?ldccp: ld a,1 ; move ccp.com from 9000h (loaded
  655. call ?bank ; there by bootrom) to 100h in
  656. ld hl,9000h ; bank 1
  657. ld de,0100h
  658. ld bc,3200
  659. ldir
  660.  
  661. ld a,2 ; also put a copy in bank 2
  662. call ?bank
  663. ld hl,9000h
  664. ld de,0100h
  665. ld bc,3200
  666. ldir
  667.  
  668. ld a,(@cbnk)
  669. call ?bank
  670. ret
  671.  
  672. ; Reload ccp
  673.  
  674. ?rlccp: ld hl,0100h ; get the copy of ccp from bank 2
  675. ld bc,3840
  676. rlccp1: ld a,2
  677. call ?bnksel
  678. ld a,(hl)
  679. push af
  680. ld a,1
  681. call ?bnksel
  682. pop af
  683. ld (hl),a
  684. inc hl
  685. dec bc
  686. ld a,b
  687. or c
  688. jr nz,rlccp1
  689. ret
  690.  
  691. ; Signal time and date operation
  692.  
  693. ?time: ret
  694.  
  695. ; Sign-on message
  696.  
  697. signon:
  698.  
  699. ; Copyright message required if using Digital Research's CP/M3 BDOS
  700.  
  701. db 'CP/M Version 3.0',cr,lf
  702. db 'Copyright 1984 by Digital Research',cr,lf,lf
  703.  
  704. db 'CBIOS '
  705. db '0'+day / 10,'0'+day mod 10,'/'
  706. db '0'+mon / 10,'0'+mon mod 10,'/'
  707. db '0'+year /10,'0'+year mod 10
  708. db cr,lf,lf
  709. if amp4
  710. db 'Drive G: Ampro 48TPI DSDD',cr,lf
  711. endif
  712. if kay4
  713. db ' H: Kaypro 4/10 DSDD',cr,lf
  714. endif
  715. db 0
  716.  
  717. ; Set source and destination banks for one operation
  718.  
  719. ?xmove: ret
  720.  
  721. ; Block move memory to memory
  722.  
  723. ?move: ex de,hl
  724. ldir
  725. ex de,hl
  726. ret
  727.  
  728. ; Select bank a = bank (0,1 or 2)
  729.  
  730. ?bank: push af
  731. push bc
  732. push hl
  733. add a,a
  734. ld c,a
  735. ld b,0
  736. ld hl,bnktbl
  737. add hl,bc
  738. ld c,(hl)
  739. in a,(c)
  740. inc hl
  741. ld c,(hl)
  742. in a,(c)
  743. pop hl
  744. pop bc
  745. pop af
  746. ret
  747.  
  748. bnktbl: db 1,2 ; Bank 0 select ports
  749. db 0,3 ; Bank 1
  750. db 1,3 ; Bank 2
  751. ;
  752. ; Initialise physical devices - CRT/KB, LPT, SIO0, SIO1
  753. ;
  754. ?cinit: ld a,c
  755. cp 0
  756. jr z,cini1 ; crt/kbd
  757. cp 1
  758. jr z,cini2 ; lpt
  759. cp 2
  760. jr z,cini3 ; sio0
  761. cp 3
  762. jr z,cini4 ; sio1
  763. ret
  764.  
  765. ; Initialise screen/keyboard
  766.  
  767. cini1: call clscrn ; clear screen, home cursor
  768. ld a,9 ; caps-lock flag off
  769. ld (caps),a
  770. ld c,a ; caps-lock led off
  771. out (c),a
  772. ret
  773.  
  774. ; Initialise printer
  775.  
  776. cini2: ret
  777.  
  778. ; Initialise serial port A
  779.  
  780. cini3: ld a,(dev2+7) ; default baudrate serial port A
  781. add a,a
  782. ld l,a
  783. ld h,0
  784. ld de,baudtbl
  785. add hl,de
  786. ld a,00110110b ; select counter 0, mode 3 binary
  787. out (timercr),a ; load 2 bytes
  788. ld a,(hl)
  789. out (timer0),a
  790. inc hl
  791. ld a,(hl)
  792. out (timer0),a
  793. ret
  794.  
  795. ; Initialise serial port B
  796.  
  797. cini4: ld a,(dev3+7) ; default baudrate serial port B
  798. add a,a
  799. ld l,a
  800. ld h,0
  801. ld de,baudtbl
  802. add hl,de
  803. ld a,01110110b ; select counter 1, mode 3 binary
  804. out (timercr),a ; load 2 bytes
  805. ld a,(hl)
  806. out (timer1),a
  807. inc hl
  808. ld a,(hl)
  809. out (timer1),a
  810. ret
  811.  
  812. ; baud rate divisor tables
  813.  
  814. baudtbl:
  815. dw 0180h ; default
  816.  
  817. dw 0900h ; 50
  818. dw 0600h ; 75
  819. dw 0417h ; 110
  820. dw 0359h ; 134.5
  821. dw 0300h ; 150
  822. dw 0180h ; 300
  823. dw 00c0h ; 600
  824. dw 0060h ; 1200
  825. dw 0040h ; 1800
  826. dw 0030h ; 2400
  827. dw 0020h ; 3600
  828. dw 0018h ; 4800
  829. dw 0010h ; 7200
  830. dw 000ch ; 9600
  831. dw 0006h ; 19200
  832. ;
  833. ; Get status of physical input device
  834. ;
  835. ?cist: ld a,b
  836. cp 0
  837. jr z,kbst ; kbd
  838. cp 1
  839. jr z,?cist1 ; lpt
  840. cp 2
  841. jr z,?cist4 ; sio0
  842. cp 3
  843. jr z,?cist6 ; sio1
  844.  
  845. ; else error
  846. ; Input status - printer
  847.  
  848. ?cist1: xor a
  849. ret
  850.  
  851. ; Input status - keyboard
  852.  
  853. kbst: ld a,(ccount) ; function key string waiting?
  854. or a
  855. jr nz,kbst1
  856. ld a,(char) ; single character waiting?
  857. cp 0ffh
  858. jr nz,kbst1
  859. in a,(pcrb) ; strobe from keyboard?
  860. and 10000000b
  861. ret z
  862. call read$kbd ; read key
  863. ld (char),a
  864. ld a,(ccount)
  865. or a
  866. ret z
  867.  
  868. kbst1: ld a,0ffh ; character available
  869. ret
  870.  
  871. ; Input status - serial port A
  872.  
  873. ?cist4: in a,(siocra)
  874. ?cist5: and 00000001b
  875. ret z
  876. ld a,0ffh
  877. ret
  878.  
  879. ; Input status - serial port B
  880.  
  881. ?cist6: in a,(siocrb)
  882. jr ?cist5
  883.  
  884. ;
  885. ; Get status of physical output device
  886. ;
  887.  
  888. ?cost: ld a,b
  889. or a
  890. jr z,?cost3 ; crt
  891. cp 1
  892. jr z,?cost2 ; lpt
  893. cp 2
  894. jr z,?cost4 ; sio0
  895. cp 3
  896. jr z,?cost6 ; sio1
  897.  
  898. ?cost1: xor a ; else error
  899. ret
  900.  
  901. ; Output status - printer
  902.  
  903. ?cost2: in a,(pddra) ; read PIA port A
  904. rra
  905. jr nc,?cost1 ; test printer busy PA0
  906.  
  907. ; Output status - screen
  908.  
  909. ?cost3: ld a,0ffh
  910. ret
  911.  
  912. ; Output status - serial port A
  913.  
  914. ?cost4: in a,(siocra)
  915. ?cost5: and 00000100b
  916. ret z
  917. ld a,0ffh
  918. ret
  919.  
  920. ; Output status - serial port B
  921.  
  922. ?cost6: in a,(siocrb)
  923. jr ?cost5
  924. ;
  925. ; Input character from physical device
  926. ;
  927. ?ci: ld a,b
  928. or a
  929. jr z,?ci6 ; kbd
  930. cp 1
  931. jr z,?ci1 ; lpt
  932. cp 2
  933. jr z,?ci2 ; sio0
  934. cp 3
  935. jr z,?ci5 ; sio1
  936.  
  937. ; else end-of-file
  938. ; Input character - printer
  939.  
  940. ?ci1: ld a,1ah
  941. ret
  942.  
  943. ; Input character - serial port a
  944.  
  945. ?ci2: ld c,siocra
  946. ld hl,maska ; get number of bits and parity
  947. ?ci3: in a,(c)
  948. and 00000001b
  949. jr z,?ci3
  950.  
  951. ld a,(hl)
  952. and 00110000b
  953. srl a
  954. srl a
  955. srl a
  956. srl a
  957. ld e,a
  958. ld d,0
  959. ld hl,?ci4
  960. add hl,de
  961. ld b,(hl)
  962. dec c ; select data register
  963. in a,(c)
  964. and b
  965. ret
  966.  
  967. ?ci4: db 00011111b ; 5 bits
  968. db 00111111b ; 6
  969. db 01111111b ; 7
  970. db 11111111b ; 8
  971.  
  972. ; Input character - serial port B
  973.  
  974. ?ci5: ld c,siocrb
  975. ld hl,maskb
  976. jr ?ci3
  977.  
  978. ; Input character - keyboard
  979.  
  980. ?ci6: ld a,(ccount) ; function key string waiting?
  981. or a
  982. jr z,?ci8
  983.  
  984. dec a ; if true, decrement count
  985. ld (ccount),a
  986. ld hl,(nxtchr) ; pointer to character
  987. ld b,(hl)
  988. inc hl
  989. ld (nxtchr),hl ; increment pointer, test next char
  990. ld a,(hl) ; if 0 then all done
  991. or a
  992. jr nz,?ci7
  993. xor a ; clear count
  994. ld (ccount),a
  995. ?ci7: ld a,b
  996. ret
  997.  
  998. ?ci8: ld a,(char) ; single character waiting?
  999. cp 0ffh
  1000. jr z,wait$key
  1001. ld hl,char
  1002. ld (hl),0ffh
  1003. ret
  1004.  
  1005. ; no characters available, wait for input from keyboard
  1006.  
  1007. wait$key:
  1008. in a,(pcrb) ; wait for cb1 (keyboard strobe)
  1009. sla a
  1010. jr nc,wait$key
  1011.  
  1012. call read$kbd
  1013. cp 0ffh
  1014. jr z,?ci6 ; loop until character or keystring
  1015. ret ; returned
  1016.  
  1017. ;
  1018. ; Read serial data from keyboard (9 bit code)
  1019. ;
  1020.  
  1021. read$kbd:
  1022. ld de,kbd$mode$tbl ; keyboard bit decode table
  1023. ld hl,0000
  1024. ld c,0
  1025. ld b,9
  1026.  
  1027. kbd$loop:
  1028. in a,(pddra) ; read pia port A
  1029. sla a
  1030. jp p,zerobit ; test PA6 (serial in) for 0 or 1
  1031.  
  1032. ; bit = 1
  1033. ld a,(de)
  1034. inc de
  1035. add a,c
  1036. ld c,a ; value of mode in C
  1037. ld a,(de)
  1038. add a,l
  1039. ld l,a ; value of key in L
  1040. dec de
  1041.  
  1042. zerobit: ; bit = 0
  1043. inc de
  1044. inc de
  1045.  
  1046. ; clock in next bit
  1047.  
  1048. ld a,00110100b
  1049. out (pcrb),a ; set keyboard shift clock CB2 low
  1050. ld a,00111100b
  1051. out (pcrb),a ; set CB2 high
  1052. djnz kbd$loop ; get all 9 bits
  1053.  
  1054. ld a,c
  1055. cp 3 ; shift-control?
  1056. jp z,shift$ctrl
  1057.  
  1058. cp 1 ; shift?
  1059. jr nz,not$shift
  1060.  
  1061. ld de,90 ; shifted keys, access second table
  1062. add hl,de
  1063.  
  1064. not$shift:
  1065. ld de,keytbl
  1066. add hl,de
  1067. ld a,(hl) ; get character from decode table
  1068. cp 0ffh
  1069. jr z,no$key
  1070. ld b,a
  1071.  
  1072. ; check for control key
  1073.  
  1074. ld a,c
  1075. cp 2 ; control key?
  1076. jr nz,?func
  1077.  
  1078. ld a,b
  1079. cp 64 ; key in-range?
  1080. jr c,no$key
  1081. cp 127+1
  1082. jr nc,no$key
  1083.  
  1084. cp 96 ; convert to uppercase?
  1085. jr c,do$ctl
  1086. sub 32
  1087. do$ctl: sub 64 ; make ascii code
  1088. ld b,a
  1089.  
  1090. ; check for function key (80-8f)
  1091.  
  1092. ?func: ld a,b
  1093. and 11110000b
  1094. cp 10000000b
  1095. jr nz,?caps
  1096.  
  1097. ; function key pressed, set up pointer to string
  1098.  
  1099. ld a,b
  1100. sla a ; *2
  1101. sla a ; *4
  1102. sla a ; *8
  1103. sla a ; *16
  1104. ld l,a
  1105. ld h,0
  1106. ld de,fntbl ; function key table
  1107. add hl,de
  1108. ld (nxtchr),hl ; set pointer
  1109. ld a,(hl) ; get first character
  1110. or a ; was it zero?
  1111. jr z,no$key
  1112. ld a,16 ; no, then set max string count
  1113. ld (ccount),a
  1114. jr no$key
  1115.  
  1116. ; check for caps-lock key
  1117.  
  1118. ?caps: ld a,b
  1119. cp 0cah ; caps-lock key?
  1120. jr nz,test$case
  1121.  
  1122. ld a,(caps) ; yes, toggle flag
  1123. xor 1
  1124. ld (caps),a
  1125. ld c,a ; toggle led
  1126. out (c),a
  1127. jr no$key ; and exit
  1128.  
  1129. ; convert key to upper/lower case according to caps flag
  1130.  
  1131. test$case:
  1132. ld hl,caps ; test flag
  1133. bit 0,(hl)
  1134. jr nz,kbd$exit
  1135.  
  1136. cp 'a' ; convert lowercase to upper
  1137. jr c,locase
  1138. cp 'z'+1
  1139. jr nc,kbd$exit
  1140. sub 32
  1141. jr kbd$exit
  1142.  
  1143. locase:
  1144. if lcase
  1145. cp 'A' ; convert uppercase to lower
  1146. jr c,kbd$exit
  1147. cp 'Z'+1
  1148. jr nc,kbd$exit
  1149. add a,32
  1150. endif
  1151.  
  1152. kbd$exit:
  1153. ld b,a
  1154. in a,(pddrb) ; clear bits 6,7
  1155. ld a,b
  1156. ret
  1157.  
  1158. no$key: ld a,0ffh ; no key
  1159. jr kbd$exit
  1160.  
  1161. ; shift-control keys - not handled in original BIOS
  1162.  
  1163. shift$ctrl:
  1164. ld a,l
  1165. cp 44
  1166. ld a,28 ; shift-ctrl \
  1167. jr z,kbd$exit
  1168. ld a,l
  1169. cp 81
  1170. ld a,31 ; shift-ctrl _
  1171. jr z,kbd$exit
  1172. jr no$key
  1173.  
  1174. ;
  1175. ; Keyboard data decode table
  1176. ;
  1177. ; bits 1,8 mode (normal, shift, control, shift-ctrl)
  1178. ; bits 2-7,9 which key in a 10*9 matrix was pressed
  1179. ;
  1180.  
  1181. kbd$mode$tbl:
  1182. db 1,0 ; 1 B3
  1183. db 0,8 ; 2 B6
  1184. db 0,2 ; 3 B0
  1185. db 0,1 ; 4 B9
  1186. db 0,4 ; 5 B7
  1187. db 0,16 ; 6 B5
  1188. db 0,32 ; 7 B4
  1189. db 2,0 ; 8 B2
  1190. db 0,64 ; 9 B1
  1191. ;
  1192. ; Output character to physical device
  1193. ;
  1194. ?co: ld a,b
  1195. or a
  1196. jr z,co6 ; crt
  1197. cp 1
  1198. jr z,co4 ; lpt
  1199. cp 2
  1200. jr z,co1 ; sio0
  1201. cp 3
  1202. jr z,co3 ; sio1
  1203. ret
  1204.  
  1205. ; Output character - serial port A
  1206.  
  1207. co1: ld b,c
  1208. ld c,siocra
  1209. co2: in a,(c)
  1210. and 00000100b
  1211. jr z,co2
  1212. ld a,b
  1213. dec c
  1214. out (c),a
  1215. ret
  1216.  
  1217. ; Output character - serial port B
  1218.  
  1219. co3: ld b,c
  1220. ld c,siocrb
  1221. jr co2
  1222.  
  1223. ; Output character - printer
  1224.  
  1225. co4: ld a,c ; output byte to port
  1226. out (pddrb),a
  1227. co5: call ?cost2 ; wait until printer is ready
  1228. or a
  1229. jr z,co5
  1230.  
  1231. nop ; then toggle strobe line
  1232. nop
  1233. nop
  1234. ld a,00110110b ; set CA2 low
  1235. out (pcra),a
  1236. nop
  1237. nop
  1238. nop
  1239. ld a,00111110b ; set CA2 high
  1240. out (pcra),a
  1241. ret
  1242.  
  1243. ; Output character - screen
  1244.  
  1245. co6: ld a,(esc) ; escape mode?
  1246. or a
  1247. jp nz,do$esc
  1248.  
  1249. ld a,(graf) ; graphic mode?
  1250. or a
  1251. jr nz,do$graph
  1252.  
  1253. ld a,c ; character in C
  1254. cp cr ; carriage return?
  1255. jp z,creturn
  1256. cp lf ; linefeed?
  1257. jr z,lfeed
  1258. cp 8 ; backspace?
  1259. jp z,bspace
  1260. cp 9 ; horizontal tab?
  1261. jp z,htab
  1262. cp 1ah ; clear screen
  1263. jp z,clscrn
  1264. cp 18h ; clear end-of-line?
  1265. jp z,cleol
  1266. cp 17h ; clear end-of-screen?
  1267. jp z,cleos
  1268. cp 0ch ; advance cursor?
  1269. jp z,advcur
  1270. cp 1eh ; home cursor?
  1271. jp z,homcur
  1272. cp 1bh ; escape key?
  1273. jp z,esc$mode
  1274. cp 0bh ; vertical tab?
  1275. jp z,vtab
  1276. cp 7 ; bell?
  1277. jr nz,vduout ; no, character is ok to print
  1278.  
  1279. ; Bell
  1280.  
  1281. beep: ld c,0
  1282. beep1: ld a,64 ; 1/4 volume
  1283. out (audio),a
  1284. ld b,40
  1285. beep2: djnz beep2
  1286. xor a ; volume off
  1287. out (audio),a
  1288. ld b,40
  1289. beep3: djnz beep3
  1290. dec c
  1291. jr nz,beep1
  1292. ret
  1293.  
  1294. ; Graphic mode
  1295.  
  1296. set$graph:
  1297. ld a,1 ; start graphic display
  1298. jr do$graph1
  1299. do$graph:
  1300. ld a,c ; if null then end graphic mode
  1301. cp 0
  1302. jr nz,vduout
  1303. xor a
  1304. do$graph1:
  1305. ld (graf),a ; set graphic flag
  1306. ret
  1307.  
  1308. ; Print character to screen
  1309.  
  1310. vduout: and 01111111b ; strip hi bit ?
  1311. ld a,(rvsflg)
  1312. or c ; mask with inverse flag
  1313. call getpos ; get current screen position (hl)
  1314. ld (hl),a ; and poke character
  1315.  
  1316. ; Advance cursor
  1317.  
  1318. advcur: ld a,(col) ; last column?
  1319. cp cols-1
  1320. jr z,advcur1 ; then crlf
  1321. inc a ; else increment column
  1322. ld (col),a
  1323. jr posit ; move it
  1324. advcur1:
  1325. xor a
  1326. ld (col),a
  1327.  
  1328. ; Line-feed
  1329.  
  1330. lfeed: ld a,(row) ; line before last?
  1331. cp rows-1
  1332. jr z,scroll
  1333. inc a ; increment line
  1334. ld (row),a
  1335. jr posit
  1336.  
  1337. ; Scroll screen
  1338.  
  1339. scroll: ld hl,screen+cols ; move lower lines up one
  1340. ld de,screen
  1341. ld bc,cols*(rows-1)
  1342. ldir
  1343. ld b,cols ; clear bottom line
  1344. ld hl,screen+cols*(rows-1)
  1345. xor a
  1346. scroll1:
  1347. ld (hl),a
  1348. inc hl
  1349. djnz scroll1
  1350.  
  1351. ; Position cursor, address in HL
  1352.  
  1353. posit: call getpos
  1354. ld a,14 ; crsr position lo register
  1355. out (crtcr),a
  1356. ld a,h
  1357. and 00000111b
  1358. out (crtdr),a
  1359. ld a,15 ; crsr position hi register
  1360. out (crtcr),a
  1361. ld a,l
  1362. out (crtdr),a
  1363. ret
  1364.  
  1365. ; Carriage return
  1366.  
  1367. creturn:
  1368. xor a
  1369. ld (col),a
  1370. jr posit
  1371.  
  1372. ; Backspace
  1373.  
  1374. bspace: ld a,(col)
  1375. dec a
  1376. jp p,bspace1
  1377. ld a,(row)
  1378. or a
  1379. ret z
  1380. dec a
  1381. ld (row),a
  1382. ld a,cols-1
  1383. bspace1:
  1384. ld (col),a
  1385. jr posit
  1386.  
  1387. ; Horizontal tab
  1388.  
  1389. htab: call advcur
  1390. ld a,(col)
  1391. and 00000111b ; until 8th column
  1392. jr nz,htab
  1393. ret
  1394.  
  1395. ; Clear to end of screen
  1396.  
  1397. cleos: call getpos
  1398. cleos1: ld (hl),0 ; should have been a 'space' but
  1399. inc hl ; left same as original BIOS
  1400. ld a,h
  1401. or l
  1402. jr nz,cleos1
  1403. ret
  1404.  
  1405. ; Clear screen, home cursor
  1406.  
  1407. clscrn: ld hl,screen
  1408. call cleos1
  1409.  
  1410. ; Home cursor
  1411.  
  1412. homcur: xor a
  1413. ld (col),a
  1414. ld (row),a
  1415. jr posit
  1416.  
  1417. ; Clear to end of line
  1418.  
  1419. cleol: call getpos
  1420. ld a,(col)
  1421. cleol1: ld (hl),0 ; see note for clear screen
  1422. inc hl
  1423. inc a
  1424. cp cols
  1425. jr nz,cleol1
  1426. ret
  1427.  
  1428. ; Vertical tab
  1429.  
  1430. vtab: ld a,(row) ; move cursor up one line
  1431. or a
  1432. ret z
  1433. dec a
  1434. ld (row),a
  1435. jr posit
  1436.  
  1437. ; Set escape mode
  1438.  
  1439. esc$mode:
  1440. ld a,3 ; set esc count
  1441. ld (esc),a
  1442. ret
  1443.  
  1444. ; Escape codes
  1445.  
  1446. do$esc: ld a,(esc) ; decrement count
  1447. dec a
  1448. ld (esc),a
  1449. cp 2 ; previous key esc?
  1450. jr nz,do$esc2
  1451.  
  1452. ld a,c
  1453. cp '=' ; cursor addressing command?
  1454. ret z
  1455.  
  1456. xor a ; clear escape flag
  1457. ld (esc),a
  1458. ld a,c ; get character, strip bit 7
  1459. and 01111111b
  1460.  
  1461. cp '*' ; esc * clear screen, home cursor
  1462. jp z,clscrn
  1463. cp 'Y' ; esc Y clear to end of screen
  1464. jp z,cleos
  1465. cp 'T' ; esc T clear to end of line
  1466. jp z,cleol
  1467. cp 'R' ; esc R delete line
  1468. jr z,delline
  1469. cp 'E' ; esc E insert line
  1470. jr z,insline
  1471. cp 0ch ; esc ^L clear screen
  1472. jp z,clscrn
  1473. cp 'G' ; esc G start graphic display
  1474. jp z,set$graph
  1475.  
  1476. ; Inverse mode
  1477.  
  1478. ld hl,rvsflg
  1479. cp 'I' ; esc I start inverse display
  1480. jr nz,do$esc1
  1481. ld (hl),128
  1482. do$esc1:
  1483. cp 'N' ; esc N end inverse display
  1484. ret nz
  1485. ld (hl),0
  1486. ret
  1487.  
  1488. ; Set cursor positioning from 'esc = yx' command
  1489.  
  1490. do$esc2:
  1491. or a ; got both arguments?
  1492. jr z,do$esc3
  1493. ld a,c ; save y argument
  1494. ld (yarg),a
  1495. ret ; return for x
  1496.  
  1497. do$esc3:
  1498. ld a,c ; subtract 32 from x
  1499. sub 32
  1500. ld (col),a
  1501. ld a,(yarg)
  1502. sub 32 ; subtract 32 from y
  1503. ld (row),a
  1504. jp posit
  1505. ;
  1506. ; Esc L - delete line
  1507. ;
  1508. delline:
  1509. xor a
  1510. ld (col),a
  1511. ld a,(row)
  1512. cp rows-1
  1513. jr z,insline1
  1514. call getpos
  1515. push hl
  1516. ld de,cols
  1517. add hl,de
  1518. ex de,hl
  1519. ld hl,screen+cols*rows
  1520. or a
  1521. sbc hl,de
  1522. ld b,h
  1523. ld c,l
  1524. pop hl
  1525. ex de,hl
  1526. ldir
  1527. xor a
  1528. ld hl,screen+cols*(rows-1)
  1529. call cleol1
  1530. jp posit
  1531. ;
  1532. ; Esc E - insert line
  1533. ;
  1534. insline:
  1535. xor a
  1536. ld (col),a
  1537. ld a,(row)
  1538. cp rows-1
  1539. jr z,insline1
  1540. call getpos
  1541. push hl
  1542. ld hl,screen+cols*(rows-1)
  1543. pop bc
  1544. or a
  1545. sbc hl,bc
  1546. ld b,h
  1547. ld c,l
  1548. ld hl,screen+cols*(rows-1)-1
  1549. ld de,screen+cols*rows-1
  1550. lddr
  1551. insline1:
  1552. call cleol
  1553. jp posit
  1554. ;
  1555. ; Get current screen position, hl returns address
  1556. ;
  1557. getpos: ld hl,(row) ; get current line
  1558. add hl,hl ; *2
  1559. add hl,hl ; *4
  1560. add hl,hl ; *8
  1561. add hl,hl ; *16
  1562. ld d,h
  1563. ld e,l
  1564. add hl,hl ; *32
  1565. add hl,hl ; *64
  1566. add hl,de
  1567. ld de,(col) ; get current column
  1568. add hl,de
  1569. ld de,screen
  1570. add hl,de
  1571. ret
  1572. ;
  1573. ; Get address of function key table HL
  1574. ;
  1575. ?fnkeys:
  1576. ld hl,fntbl
  1577. ret
  1578.  
  1579. ; Misc variables
  1580.  
  1581. ccount: db 0 ; # characters remaining in string
  1582. nxtchr: dw 0 ; pointer to next character in string
  1583. caps: db 9 ; caps-lock flag 8=on, 9=off
  1584. esc: db 0 ; esc mode 0=off
  1585. yarg: db 0 ; Y argument of 'esc = yx'
  1586. row: dw 0 ; current line
  1587. col: dw 0 ; current column
  1588. graf: db 0 ; graphic mode 0=off, 1=on
  1589. char: db 0ffh ; single keyboard character
  1590. rvsflg: db 0 ; inverse mask 0=normal, 128=inverse
  1591.  
  1592. ; Keyboard matrix - ascii decode tables
  1593.  
  1594. keytbl: db 37h,38h,39h,30h,31h,32h,33h,34h,35h,36h
  1595. db 75h,69h,6fh,70h,71h,77h,65h,72h,74h,79h
  1596. db 8eh,8fh,0dh,2eh,20h,0cah,8ah,8bh,8ch,8dh
  1597. db 86h,87h,88h,89h,80h,81h,82h,83h,84h,85h
  1598. db 13h,04h,33h,08h,40h,0ffh,2dh,5dh,05h,18h
  1599. db 39h,18h,32h,0ah,7fh,09h,5eh,5bh,37h,38h
  1600. db 6dh,2ch,2eh,2fh,7ah,78h,63h,76h,62h,6eh
  1601. db 6ah,6bh,6ch,3bh,61h,73h,64h,66h,67h,68h
  1602. db 36h,2dh,31h,30h,1bh,0ffh,3ah,0dh,34h,35h
  1603.  
  1604. db 27h,28h,29h,7ch,21h,22h,23h,24h,25h,26h
  1605. db 55h,49h,4fh,50h,51h,57h,45h,52h,54h,59h
  1606. db 8eh,8fh,0dh,2eh,20h,0cah,8ah,8bh,8ch,8dh
  1607. db 86h,87h,88h,89h,80h,81h,82h,83h,84h,85h
  1608. db 13h,04h,33h,08h,5ch,0ffh,3dh,7dh,05h,18h
  1609. db 39h,60h,32h,0ah,7fh,09h,7eh,7bh,37h,38h
  1610. db 4dh,3ch,3eh,3fh,5ah,58h,43h,56h,42h,4eh
  1611. db 4ah,4bh,4ch,2bh,41h,53h,44h,46h,47h,48h
  1612. db 36h,5fh,31h,30h,1bh,0ffh,2ah,0dh,34h,35h
  1613.  
  1614. ; Strings assigned to the 16 function keys
  1615.  
  1616. fntbl: db 'DIR ',0,0,0,0,0,0,0,0,0,0,0,0
  1617. db 'ERASE ',0,0,0,0,0,0,0,0,0,0
  1618. db 'RENAME ',0,0,0,0,0,0,0,0,0
  1619. db 'TYPE ',0,0,0,0,0,0,0,0,0,0,0
  1620. db 'DATE ',0,0,0,0,0,0,0,0,0,0,0
  1621. db 'DEVICE ',0,0,0,0,0,0,0,0,0
  1622. db 'ED ',0,0,0,0,0,0,0,0,0,0,0,0,0
  1623. db 'GET ',0,0,0,0,0,0,0,0,0,0,0,0
  1624. db 'HELP ',0,0,0,0,0,0,0,0,0,0,0
  1625. db 'PIP ',0,0,0,0,0,0,0,0,0,0,0,0
  1626. db 'PUT ',0,0,0,0,0,0,0,0,0,0,0,0
  1627. db 'SET ',0,0,0,0,0,0,0,0,0,0,0,0
  1628. db 'SETDEF ',0,0,0,0,0,0,0,0,0
  1629. db 'SHOW ',0,0,0,0,0,0,0,0,0,0,0
  1630. db 'SUBMIT ',0,0,0,0,0,0,0,0,0
  1631. db 'SETUP ',0,0,0,0,0,0,0,0,0,0
  1632.  
  1633. ; Serial port parameters - must follow fn key strings (used by SETUP)
  1634.  
  1635. maska: db 00100100b ; 7 bits, even parity
  1636. maskb: db 00100100b
  1637.  
  1638. ; Device definition table
  1639.  
  1640. mbin equ 00000001b ; input
  1641. mbout equ 00000010b ; output
  1642. mbsb equ 00000100b ; software selectable baudrate
  1643. mbser equ 00001000b ; serial
  1644. mbx equ 00010000b ; xon-xoff
  1645.  
  1646. ; Baudrate
  1647.  
  1648. bnone equ 0
  1649. b50 equ 1
  1650. b75 equ 2
  1651. b110 equ 3
  1652. b134 equ 4
  1653. b150 equ 5
  1654. b300 equ 6
  1655. b600 equ 7
  1656. b1200 equ 8
  1657. b1800 equ 9
  1658. b2400 equ 10
  1659. b3600 equ 11
  1660. b4800 equ 12
  1661. b7200 equ 13
  1662. b9600 equ 14
  1663. b19200 equ 15
  1664.  
  1665. @ctbl:
  1666.  
  1667. dev0: db 'CRT/KB',mbin+mbout,bnone
  1668. dev1: db 'LPT ',mbout,bnone
  1669. dev2: db 'SIO0 ',mbin+mbout+mbsb,b300
  1670. dev3: db 'SIO1 ',mbin+mbout+mbsb,b300
  1671. db 0
  1672.  
  1673. ; Disk definition table logical drive
  1674.  
  1675. @dtbl: dw xdph$a ; Bondwell 14
  1676. dw xdph$b ; Bondwell 14
  1677. if bw12
  1678. dw xdph$c ; Bondwell 12
  1679. else
  1680. dw 0
  1681. endif
  1682. if sv3
  1683. dw xdph$d ; Spectravideo
  1684. else
  1685. dw 0
  1686. endif
  1687. if kay2
  1688. dw xdph$e ; Kaypro II
  1689. else
  1690. dw 0
  1691. endif
  1692. if osb1
  1693. dw xdph$f ; Osborne I
  1694. else
  1695. dw 0
  1696. endif
  1697. if amp4
  1698. dw xdph$g ; Ampro DSDD 48 tpi
  1699. else
  1700. dw 0
  1701. endif
  1702. if kay4
  1703. dw xdph$h ; Kaypro 4/10
  1704. else
  1705. dw 0
  1706. endif
  1707.  
  1708. dw 0,0,0,0,0,0,0,0 ; I-P unused drives
  1709.  
  1710. ; Extended disk parameter headers, one for each logical drive.
  1711. ; CSV, ALV, DIRBCB, DTABCB, HASH for each xdph are automatically
  1712. ; allocated by GENCPM.
  1713.  
  1714. csv equ 0fffeh
  1715. alv equ 0fffeh
  1716. dirbcb equ 0fffeh
  1717. dtabcb equ 0fffeh
  1718. hash equ 0fffeh
  1719.  
  1720. dr0 equ 0 ; physical drive 0
  1721. dr1 equ 1 ; physical drive 1
  1722.  
  1723. ; Drive A Bondwell 14
  1724.  
  1725. dw wr256 ; write
  1726. dw rd256 ; read
  1727. dw dvlog ; login
  1728. dw dvinit ; init
  1729. db dr0,0 ; physical drive
  1730. xdph$a: dw 0 ; xlt
  1731. db 0,0,0,0,0,0,0,0,0,0
  1732. dw dpb1 ; dpb
  1733. dw csv ; csv
  1734. dw alv ; alv
  1735. dw dirbcb ; dirbcb
  1736. dw dtabcb ; dtabcb
  1737. dw hash ; hash
  1738. db 0 ; hbank
  1739.  
  1740. ; Drive B Bondwell 14
  1741.  
  1742. dw wr256
  1743. dw rd256
  1744. dw dvlog
  1745. dw dvinit
  1746. db dr1,0
  1747. xdph$b: dw 0
  1748. db 0,0,0,0,0,0,0,0,0,0
  1749. dw dpb1
  1750. dw csv
  1751. dw alv
  1752. dw dirbcb
  1753. dw dtabcb
  1754. dw hash
  1755. db 0
  1756.  
  1757. ; Drive C Bondwell 12
  1758.  
  1759. if bw12
  1760. dw wr256
  1761. dw rd256
  1762. dw dvlog
  1763. dw dvinit
  1764. db dr1,0
  1765. xdph$c: dw 0
  1766. db 0,0,0,0,0,0,0,0,0,0
  1767. dw dpb2
  1768. dw csv
  1769. dw alv
  1770. dw dirbcb
  1771. dw dtabcb
  1772. dw hash
  1773. db 0
  1774. endif
  1775.  
  1776. ; Drive D Spectravideo 318/328
  1777.  
  1778. if sv3
  1779. dw wr256
  1780. dw rd256
  1781. dw dvlog
  1782. dw dvinit
  1783. db dr1,0
  1784. xdph$d: dw xlt2
  1785. db 0,0,0,0,0,0,0,0,0,0
  1786. dw dpb3
  1787. dw csv
  1788. dw alv
  1789. dw dirbcb
  1790. dw dtabcb
  1791. dw hash
  1792. db 0
  1793. endif
  1794.  
  1795. ; Drive E Kaypro II
  1796.  
  1797. if kay2
  1798. dw wr512
  1799. dw rd512
  1800. dw dvlog
  1801. dw dvinit
  1802. db dr1,0
  1803. xdph$e: dw 0
  1804. db 0,0,0,0,0,0,0,0,0,0
  1805. dw dpb4
  1806. dw csv
  1807. dw alv
  1808. dw dirbcb
  1809. dw dtabcb
  1810. dw hash
  1811. db 0
  1812. endif
  1813.  
  1814. ; Drive F Osborne I
  1815.  
  1816. if osb1
  1817. dw wr1024
  1818. dw rd1024
  1819. dw dvlog
  1820. dw dvinit
  1821. db dr1,0
  1822. xdph$f: dw xlt2
  1823. db 0,0,0,0,0,0,0,0,0,0
  1824. dw dpb5
  1825. dw csv
  1826. dw alv
  1827. dw dirbcb
  1828. dw dtabcb
  1829. dw hash
  1830. db 0
  1831. endif
  1832.  
  1833. ; Drive G Ampro DSDD 48tpi
  1834.  
  1835. if amp4
  1836. dw wr512
  1837. dw rd512
  1838. dw dvlog
  1839. dw dvinit
  1840. db dr1,0
  1841. xdph$g: dw xlt3
  1842. db 0,0,0,0,0,0,0,0,0,0
  1843. dw dpb6
  1844. dw csv
  1845. dw alv
  1846. dw dirbcb
  1847. dw dtabcb
  1848. dw hash
  1849. db 0
  1850. endif
  1851.  
  1852. ; Drive H Kaypro 4/10 DSDD
  1853.  
  1854. if kay4
  1855. dw wr512
  1856. dw rd512
  1857. dw dvlog
  1858. dw dvinit
  1859. db dr1,0
  1860. xdph$h: dw xlt1
  1861. db 0,0,0,0,0,0,0,0,0,0
  1862. dw dpb7
  1863. dw csv
  1864. dw alv
  1865. dw dirbcb
  1866. dw dtabcb
  1867. dw hash
  1868. db 0
  1869. endif
  1870.  
  1871. ; Disk parameter blocks for each disk format
  1872.  
  1873. ; Bondwell 14
  1874. dpb1: dw 36 ; SPT 36 logical sectors per track
  1875. db 4 ; BSH 2k block size
  1876. db 15 ; BLM
  1877. db 1 ; EXM
  1878. dw 174 ; DSM 175 blocks
  1879. dw 127 ; DRM 128 directory entries
  1880. db 192 ; AL0 2 directory blocks
  1881. db 0 ; AL1
  1882. dw 32 ; CKS
  1883. dw 2 ; OFF 2 reserved tracks
  1884. db 1 ; PSH
  1885. db 1 ; PHM 2 logical per physical sectors
  1886.  
  1887. if bw12
  1888. dpb2: dw 36 ; Bondwell 12
  1889. db 4
  1890. db 15
  1891. db 1
  1892. dw 84
  1893. dw 127
  1894. db 192
  1895. db 0
  1896. dw 32
  1897. dw 2
  1898. db 1
  1899. db 1
  1900. endif
  1901.  
  1902. if sv3
  1903. dpb3: dw 34 ; Spectravideo SV318/328
  1904. db 3
  1905. db 7
  1906. db 0
  1907. dw 156
  1908. dw 63
  1909. db 192
  1910. db 0
  1911. dw 16
  1912. dw 3
  1913. db 1
  1914. db 1
  1915. endif
  1916.  
  1917. if kay2
  1918. dpb4: dw 40 ; Kaypro II
  1919. db 3
  1920. db 7
  1921. db 0
  1922. dw 194
  1923. dw 63
  1924. db 240
  1925. db 0
  1926. dw 16
  1927. dw 1
  1928. db 2
  1929. db 3
  1930. endif
  1931.  
  1932. if osb1
  1933. dpb5: dw 40 ; Osborne 1
  1934. db 3
  1935. db 7
  1936. db 0
  1937. dw 184
  1938. dw 63
  1939. db 192
  1940. db 0
  1941. dw 16
  1942. dw 3
  1943. db 3
  1944. db 7
  1945. endif
  1946.  
  1947. if amp4
  1948. dpb6: dw 40 ; Ampro dsdd 48tpi
  1949. db 4
  1950. db 15
  1951. db 1
  1952. dw 194
  1953. dw 127
  1954. db 192
  1955. db 0
  1956. dw 32
  1957. dw 2
  1958. db 2
  1959. db 3
  1960. endif
  1961.  
  1962. if kay4
  1963. dpb7: dw 40 ; Kaypro 4/10
  1964. db 4
  1965. db 15
  1966. db 1
  1967. dw 196
  1968. dw 63
  1969. db 128
  1970. db 0
  1971. dw 16
  1972. dw 1
  1973. db 2
  1974. db 3
  1975. endif
  1976.  
  1977. ; Translate tables
  1978.  
  1979. xlt1: db 0
  1980. xlt2: db 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
  1981. xlt3: db 17,18,19,20,21,22,23,24,25,26
  1982.  
  1983. ;
  1984. ; Disk drive controller routines
  1985. ;
  1986.  
  1987. ; initialise drive
  1988.  
  1989. dvinit:
  1990.  
  1991. ; login drive - determine disk parameters, load DPB
  1992.  
  1993. dvlog: ret
  1994.  
  1995. ; read/write - 256 byte sectors
  1996.  
  1997. rd256: call setrd
  1998. jr rw256
  1999.  
  2000. wr256: call setwrt
  2001.  
  2002. rw256: ld a,(@sect) ; sector
  2003. ld (putbuf+4),a
  2004. ld a,1 ; 256 bytes
  2005. ld (putbuf+5),a
  2006. ld a,10 ; gap length
  2007. ld (putbuf+7),a
  2008. ld a,1
  2009. ld (blocks),a
  2010. jp rwsec
  2011.  
  2012. ; read/write - 512 byte sectors
  2013.  
  2014. rd512: call setrd
  2015. jr rw512
  2016.  
  2017. wr512: call setwrt
  2018.  
  2019. rw512: ld a,(@sect)
  2020.  
  2021. ; sector modification for kaypro 4/10
  2022.  
  2023. if kay4
  2024. ld b,a
  2025. ld a,(@adrv)
  2026. cp 7 ; drive H
  2027. ld a,b
  2028. jr nz,nosec
  2029. ld a,(@trk)
  2030. srl a
  2031. ld a,b
  2032. jr nc,nosec
  2033. ; odd tracks = side 1
  2034. add a,10 ; change sector number
  2035. nosec:
  2036. endif
  2037.  
  2038. ld (putbuf+4),a
  2039. ld a,2 ; 512 bytes
  2040. ld (putbuf+5),a
  2041. ld a,42 ; gap length
  2042. ld (putbuf+7),a
  2043. ld a,2
  2044. ld (blocks),a
  2045. jp rwsec
  2046.  
  2047. ; read/write - 1024 byte sectors
  2048.  
  2049. rd1024: call setrd
  2050. jr rw1024
  2051.  
  2052. wr1024: call setwrt
  2053.  
  2054. rw1024: ld a,(@sect)
  2055. ld (putbuf+4),a
  2056. ld a,3 ; 1024 bytes
  2057. ld (putbuf+5),a
  2058. ld a,128 ; gap length
  2059. ld (putbuf+7),a
  2060. ld a,4
  2061. ld (blocks),a
  2062. jr rwsec
  2063.  
  2064. ; common sector read/write routine
  2065.  
  2066. rwsec: ld a,(@dbnk) ; set bank for i/o
  2067. call ?bank
  2068. ld a,(hddrv)
  2069. ld (putbuf+1),a ; head/drive
  2070. srl a
  2071. srl a
  2072.  
  2073. ; ignore side check for Kaypro 4/10
  2074.  
  2075. if kay4
  2076. ld e,a
  2077. ld a,(@adrv)
  2078. cp 7 ; drive H
  2079. ld a,e
  2080. jr nz,chkok
  2081. ld a,0 ; side ID always 0
  2082. chkok:
  2083. endif
  2084.  
  2085. ld (putbuf+3),a ; side ID
  2086. ld a,(track)
  2087. ld (putbuf+2),a ; track ID
  2088.  
  2089. ld a,maxtry ; maximum error retries
  2090. ld (dskerr),a
  2091.  
  2092. rwsec1: ld a,(blocks) ; # 256 byte blocks per physical sector
  2093. ld d,a
  2094. ld b,0
  2095. ld c,9 ; send read/write command
  2096. call putfdc
  2097. ld hl,(@dma)
  2098.  
  2099. call waitint ; wait for request
  2100.  
  2101. ; physical sector read or write
  2102.  
  2103. rwsec2: jp 0000 ; *** self-modifying code ***
  2104. ; jump to sector read / write
  2105.  
  2106. rd$byt: in a,(fdcdr) ; read a byte
  2107. ld (hl),a
  2108. jr rwsec3
  2109.  
  2110. wr$byt: ld a,(hl) ; write a byte
  2111. out (fdcdr),a
  2112.  
  2113. rwsec3: inc hl ; inc buffer pointer
  2114. djnz rwsec4
  2115. dec d ; done whole sector?
  2116. jr nz,rwsec4
  2117.  
  2118. call tc ; terminate command
  2119. call waitint
  2120. ld c,7 ; get result from fdc
  2121. call getfdc
  2122. ld a,(getbuf) ; status st0
  2123. and 11000000b
  2124. jr nz,rwsec5
  2125. jr rwsec7
  2126.  
  2127. rwsec4: in a,(pddra) ; wait for fdc to signal next data byte
  2128. rla
  2129. jr c,rwsec2
  2130. in a,(pddra)
  2131. rla
  2132. jr c,rwsec2
  2133. in a,(pddra)
  2134. rla
  2135. jr c,rwsec2
  2136. in a,(pddra)
  2137. rla
  2138. jr c,rwsec2
  2139. in a,(pddra)
  2140. rla
  2141. jr c,rwsec2
  2142.  
  2143. ld c,6 ; fdc error - timed-out
  2144. call getfdc
  2145. rwsec5: ld a,(dskerr) ; error, decrement count
  2146. dec a
  2147. ld (dskerr),a
  2148.  
  2149. cp maxtry/2 ; try recalibration?
  2150. jr nz,rwsec6
  2151.  
  2152. ld hl,putbuf ; save current fdc command
  2153. ld de,tmpbuf
  2154. ld bc,9
  2155. ldir
  2156. call drvcal ; recalibrate drive
  2157. call seek ; restore track
  2158. ld hl,tmpbuf
  2159. ld de,putbuf
  2160. ld bc,9
  2161. ldir
  2162. jp rwsec1
  2163.  
  2164. rwsec6: or a ; err count reached zero?
  2165. jp nz,rwsec1
  2166.  
  2167. if errors
  2168. call ?pderr ; display track, sector error
  2169. endif
  2170.  
  2171. ld a,1
  2172. rwsec7: push af ; restore bank
  2173. ld a,(@cbnk)
  2174. call ?bank
  2175. in a,(0ah) ; de-select both drives
  2176. in a,(0ch)
  2177. pop af
  2178. ret
  2179.  
  2180. blocks: db 0 ; number of 256 byte blocks per sector
  2181. ; for read/write
  2182.  
  2183. dskerr: db 0 ; read/write error count
  2184.  
  2185. ; Recalibrate drive
  2186.  
  2187. drvcal: call waitcmd
  2188. call drvstat ; get drive status
  2189. ld a,(getbuf)
  2190. and 00100000b
  2191. jr z,drvcal ; wait till drive is ready
  2192. call waitcmd
  2193. ld hl,(@recal) ; 2 bytes
  2194. ld (putbuf),hl
  2195. ld a,(@rdrv)
  2196. inc a
  2197. ld (putbuf+1),a
  2198. ld c,2
  2199. call putfdc
  2200. call waitint
  2201. call sintfdc
  2202. ld a,(getbuf)
  2203. and 11110000b
  2204. cp 00100000b
  2205. ret
  2206.  
  2207. ; Turn drive on, seek track, set read/write command for FDC
  2208.  
  2209. setrd: ld hl,rd$byt
  2210. ld (rwsec2+1),hl
  2211. call drvon
  2212. call seek
  2213. call waitcmd
  2214. ld hl,@read
  2215. jr setrw1
  2216.  
  2217. setwrt: ld hl,wr$byt
  2218. ld (rwsec2+1),hl
  2219. call drvon
  2220. call drvstat
  2221. ld a,(getbuf)
  2222. and 01000000b ; write protected?
  2223. jr z,setrw
  2224. pop hl
  2225. ld a,2
  2226. jp rwsec7 ; abort
  2227.  
  2228. setrw: call seek
  2229. call waitcmd
  2230. ld hl,@write
  2231. setrw1: ld de,putbuf ; load fdc command buffer
  2232. ld bc,9
  2233. ldir
  2234. ret
  2235.  
  2236. ; Turn drive on
  2237.  
  2238. drvon: ld a,(@rdrv) ; get current drive
  2239. or a
  2240. jr z,drvon1
  2241. ld b,0dh ; setup for drive B on
  2242. ld c,0ah ; drive A off
  2243. jr drvon2
  2244.  
  2245. drvon1: ld b,0bh ; setup for drive A on
  2246. ld c,0ch ; drive B off
  2247. drvon2: in a,(pddra) ; get motor status
  2248. out (c),a ; select current drive
  2249. ld c,b
  2250. out (c),a ; deselect other drive
  2251. and 00001000b ; was drive already on?
  2252. ret nz ; then return
  2253. ld de,120 ; else allow to reach speed (1000 mS)
  2254. jp vdelay
  2255.  
  2256. ; Seek track
  2257.  
  2258. seek: call waitcmd
  2259. ld hl,@seek
  2260. ld de,putbuf
  2261. ld bc,3
  2262. ldir
  2263. ld hl,@rdrv
  2264.  
  2265. ld a,(@adrv)
  2266.  
  2267. if amp4
  2268. cp 6 ; G: Ampro 48tpi
  2269. jr z,seek2
  2270. endif
  2271.  
  2272. if kay4
  2273. cp 7 ; H: Kaypro 4/10
  2274. jr z,seek2
  2275. endif
  2276.  
  2277. ld a,(@trk) ; convert logical to physical track
  2278. cp 40 ; over 39?
  2279. jr nc,seek1
  2280. ld (track),a ; no, head=0
  2281. xor a
  2282. jr seek3
  2283.  
  2284. seek1: sub 40 ; else head=1
  2285. ld (track),a
  2286. ld a,00000100b
  2287. jr seek3
  2288.  
  2289. seek2: ld a,(@trk) ; odd numbered tracks use head #1
  2290. srl a ; divide by 2
  2291. ld (track),a
  2292. rla ; get overflow from carry
  2293. and 00000001b
  2294. jr z,seek3
  2295. sla a ; set bit 2
  2296. sla a
  2297. seek3: or (hl)
  2298. inc a
  2299. ld (hddrv),a
  2300. ld (putbuf+1),a
  2301. ld a,(track)
  2302. ld (putbuf+2),a
  2303. ld c,3
  2304. call putfdc
  2305. call waitint
  2306. call sintfdc
  2307. ld a,(getbuf)
  2308. and 00100000b ; seek completed?
  2309. jr z,seek
  2310. ret
  2311.  
  2312. ; Service FDC interrupt
  2313.  
  2314. sintfdc:
  2315. call waitcmd
  2316. ld a,(@sense) ; 1 byte
  2317. ld (putbuf),a
  2318. ld c,1
  2319. call putfdc
  2320. ld c,2
  2321. call getfdc
  2322. ret
  2323.  
  2324. ; Sense disk status
  2325.  
  2326. drvstat:
  2327. call waitcmd
  2328. ld hl,(@stat) ; 2 bytes
  2329. ld (putbuf),hl
  2330. ld a,(@rdrv)
  2331. inc a
  2332. ld (putbuf+1),a
  2333. ld c,2
  2334. call putfdc
  2335. ld c,1
  2336. call getfdc
  2337. ret
  2338.  
  2339. ; Put C bytes to FDC
  2340.  
  2341. putfdc: ld hl,putbuf
  2342. putfd1: call delay
  2343. in a,(fdcst)
  2344. and 11000000b
  2345. cp 10000000b
  2346. jr nz,putfd1
  2347.  
  2348. ld a,(hl)
  2349. out (fdcdr),a
  2350. inc hl
  2351. dec c
  2352. jr nz,putfd1
  2353. ret
  2354.  
  2355. ; Get C bytes from FDC
  2356.  
  2357. getfdc: ld hl,getbuf
  2358. getfd1: call delay
  2359. in a,(fdcst)
  2360. and 11000000b
  2361. cp 11000000b
  2362. jr nz,getfd1
  2363.  
  2364. in a,(fdcdr)
  2365. ld (hl),a
  2366. inc hl
  2367. dec c
  2368. jr nz,getfd1
  2369. ret
  2370.  
  2371. ; Variable delay DE * 8.5 mS approx
  2372.  
  2373. vdelay: ld b,0
  2374. vdelay1:
  2375. call delay
  2376. djnz vdelay1
  2377. dec de
  2378. ld a,d
  2379. or e
  2380. jr nz,vdelay
  2381. ret
  2382.  
  2383. ; Set / reset TC input (terminate FDC command)
  2384.  
  2385. tc: out (0fh),a ; set TC high
  2386. call delay
  2387. call delay
  2388. out (0eh),a ; set TC low
  2389. ret
  2390.  
  2391. ; Wait until FDC is ready to accept a command
  2392.  
  2393. waitcmd:
  2394. call delay
  2395. in a,(fdcst)
  2396. and 00110000b
  2397. jr nz,waitcmd
  2398. ret
  2399.  
  2400. ; Wait until FDC issues interrupt
  2401.  
  2402. waitint:
  2403. nop
  2404. in a,(pddra)
  2405. rla
  2406. jr nc,waitint
  2407. ret
  2408.  
  2409. ; Small delay 32uS (including CALL)
  2410.  
  2411. delay: ex (sp),ix
  2412. ex (sp),ix
  2413. ex (sp),ix
  2414. ex (sp),ix
  2415. ret
  2416.  
  2417. ; FDC commands
  2418.  
  2419. @seek: db 0fh,1,0
  2420. @sense: db 8
  2421. @read: db 46h,1,0,0,1,1,12h,0ah,0ffh
  2422. @write: db 45h,1,0,0,1,1,12h,0ah,0ffh
  2423. @stat: db 4,1
  2424. @recal: db 7,1
  2425.  
  2426. putbuf: ds 9 ; fdc send buffer
  2427. getbuf: ds 7 ; fdc get buffer
  2428. tmpbuf: ds 9 ; temp command buffer
  2429. hddrv: ds 1 ; head/drive
  2430. track: ds 1 ; physical track
  2431.  
  2432. end
  2433.  
Advertisement
Add Comment
Please, Sign In to add comment