home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ENTERPRS / CPM / UTILS / A / CPM22EM.AZM / CPM22EM.ASM
Assembly Source File  |  2000-06-30  |  12KB  |  498 lines

  1. ; ============================================================================
  2. ; *                 CP/M 2.2 BIOS EMULATOR FOR CP/M 3.x                      *
  3. ; ============================================================================
  4. ;  This program, by Mike Griswold, is a Resident System Extension (RSX) which
  5. ;  runs under CP/M-Plus.  This RSX intercepts certain BIOS function calls,
  6. ;  and resolves differences between CP/M 2.2 and CP/M 3.x.  It allows many
  7. ;  programs that do not normally work with CP/M-Plus to work correctly.
  8. ;  So far, I have installed this RSX on DU2, which normally does not work
  9. ;  at all, and with the RSX, it works perfectly.
  10. ;  Installation instructions:
  11. ;      1. RMAC CPM22 $pz $sz
  12. ;      2. LINK CPM22[OP]
  13. ;      3. REN CPM22.RSX=CPM22.PRL
  14. ;      4. GENCOM <program name> CPM22
  15. ;        NOTE:  <program name> is a .COM file which is the CP/M 2.2 command
  16. ;             file.  
  17. ;
  18. ;  Program typed from Doctor Dobbs Journal #93, July 1984.
  19. ;     Typed & Instructions written by Charles Foreman.
  20. ;     Uploaded to CURA RCP/M - (212) 625-5931 - by Charles Foreman.
  21. ;
  22. ;
  23.     title    'CP/M 2.2 BIOS RSX'
  24. ;
  25. ;    18Jan84            By Mike Griswold
  26. ;
  27. ;    This RSX will provide CP/M 2.2 compatible BIOS support
  28. ;    for CP/M 3.x.  Primarily it performs logical sector
  29. ;    blocking and deblocking needed for some programs.
  30. ;    All actual I/O is done by the CP/M 3.0 BIOS.
  31. ;
  32.     maclib    z80        ; Z80 opcode equates
  33.     cseg
  34. ;
  35. ;    This equate is the only hardware dependant value.
  36. ;    It should be set to the largest sector size that 
  37. ;       will be used.
  38. ;
  39. max$sector$size:    equ    512
  40. ;
  41. ;
  42. ;    RSX prefix structure
  43. ;
  44.     db    0,0,0,0,0,0
  45. entry:    jmp    boot
  46. next:    db    jmp        ; jump
  47.     dw    0        ; next module in line
  48. prev:    db    0        ; previous module
  49. remove:    db    00fh        ; remove flag
  50. nonbnk:    db    0
  51.     db    'BIOS2.21'
  52.     db    0,0,0
  53. ;
  54. ;    Align jump table on next page boundary.  This is needed
  55. ;    for programs that cheat when getting the addresses of
  56. ;    BIOS jump table entries.  Optimization freaks could move
  57. ;    some code up here.  With a 60k TPA though its hard to
  58. ;    get excited.
  59. ;
  60.     ds    229
  61. ;
  62. ;    BIOS Jump Table
  63. ;
  64. cbt:    jmp    wboot        ; cold boot entry
  65. wbt:    jmp    wboot        ; warm boot entry
  66.     jmp    xconst        ; console status
  67.     jmp    xconin        ; console input
  68.     jmp    xconout        ; console output
  69.     jmp    xlist        ; list output
  70.     jmp    xauxout        ; aux device output
  71.     jmp    xauxin        ; aux device input
  72.     jmp    home        ; home disk head
  73.     jmp    seldsk        ; select drive
  74.     jmp    settrk        ; select track
  75.     jmp    setsec        ; select sector
  76.     jmp    setdma        ; set dma address
  77.     jmp    read        ; read a sector
  78.     jmp    write        ; write a sector
  79.     jmp    xlistst        ; list status
  80.     jmp    sectran        ; sector translation
  81. ;
  82. ;    The CP/M 3.0 BIOS jump table is copied here
  83. ;    to allow easy access to its routines.  The disk
  84. ;    I/O routines are potentially in banked memory
  85. ;    so they cannot be called directly.
  86. ;
  87. xwboot:    jmp    0        ; warm boot
  88. xconst:    jmp    0
  89. xconin:    jmp    0
  90. xconout:jmp    0
  91. xlist:    jmp    0
  92. xauxout:jmp    0
  93. xauxin:    jmp    0
  94.     jmp    0
  95.     jmp    0
  96.     jmp    0
  97.     jmp    0
  98.     jmp    0
  99.     jmp    0
  100.     jmp    0
  101. xlistst:jmp    0
  102. ;
  103. ;    Signon message
  104. ;
  105. signon:    db    0dh,0ah,'BIOS ver 2.21 ACTIVE',0dh,0ah,0
  106. ;
  107. ;    Cold boot
  108. ;
  109. boot:    push    psw        ; a BDOS call is in progress
  110.     push    h        ; so save CPU state
  111.     push    d
  112.     push    b
  113.     lxi    h,next        ; now bypass this RSX on
  114.     shld    entry+1        ; all subsequent BDOS calls
  115.     call    init        ; initialize BIOS variables
  116.     lhld    1        ; save the CP/M 3.0 BIOS jump
  117.     shld    old$addr    ; at location 0
  118.     lxi    d,xwboot    ; set up to move jump table
  119.     lxi    b,15*3        ; byte count
  120.     ldir
  121.     lxi    h,wbt        ; substitute new jump address
  122.     shld    1
  123.     lxi    h,signon    ; sound off
  124.     call    prmsg
  125.     pop    b        ; restore BDOS call state
  126.     pop    d
  127.     pop    h
  128.     pop    psw
  129.     jmp    next        ; carry on
  130. ;
  131. ;    Warm boot
  132. ;
  133. wboot:    lhld    old$addr
  134.     shld    1        ; restore normal BIOS address
  135.     jmp    0        ; jump to CP/M 3.0 warm boot
  136. ;
  137. ;    Initialize BIOS internal variables for cold boot
  138. ;
  139. init:    xra    a
  140.     sta    hstwrt        ; host buffer written
  141.     sta    hstact        ; host buffer inactive
  142.     lxi    h,80h
  143.     shld    dmaadr
  144.     ret
  145. ;
  146. ;    Routine to call banked BIOS routines via BDOS
  147. ;    function 50.  All disk I/O calls are made through
  148. ;    here.
  149. ;
  150. xbios:    sta    biospb        ; set BIOS function
  151.     mvi    c,50        ; direct BIOS call function
  152.     lxi    d,biospb    ; BIOS parameter block
  153.     jmp    next        ; jump to BDOS
  154. ;
  155. biospb:    db    0        ; BIOS function
  156. areg:    db    0        ; A reguster
  157. bcreg:    dw    0        ; BC register
  158. dereg:    dw    0        ; DE register
  159. hlreg:    dw    0        ; HL register
  160. ;
  161. ;    Home disk.
  162. ;
  163. home:    lda    hstwrt        ; check if pending write
  164.     ora    a
  165.     cnz    writehst    ; dump buffer to disk
  166.     xra    a
  167.     sta    hstwrt        ; buffer written
  168.     sta    hstact        ; buffer inactive
  169.     sta    unacnt        ; zero alloc count
  170.     sta    sektrk        ; zero track count
  171.     sta    sektrk+1
  172.     ret
  173. ;
  174. ;    Select disk.  Create a fake DPH for programs
  175. ;    that might use it.
  176. ;
  177. seldsk:    mov    a,c        ; requested drive number
  178.     sta    sekdsk
  179.     sta    bcreg        ; set C reg in BIOSPB
  180.     mvi    a,9        ; BIOS function number
  181.     call    xbios        ; CP/M 3.0 select
  182.     mov    a,h
  183.     ora    l        ; check for HL=0
  184.     rz            ; select error
  185.     mov    e,m        ; get address of xlat table
  186.     inx    h
  187.     mov    d,m
  188.     xchg
  189.     shld    xlat        ; save xlat address
  190.     lxi    h,11        ; offset to dpb address
  191.     dad    d
  192.     mov    e,m        ; fetch address to dpb
  193.     inx    h
  194.     mov    d,m
  195.     xchg
  196.     shld    dpb        ; address of dpb
  197.     mov    a,m        ; cpm sectors per track
  198.     sta    spt
  199.     inx    h
  200.     inx    h        ; point to block shift mask
  201.     inx    h
  202.     mov    a,m
  203.     sta    bsm        ; save block shift mask
  204.     lxi    d,12        ; offset to psh
  205.     dad    d
  206.     mov    a,m
  207.     sta    psh        ; save physical shift factor
  208.     lxi    h,dph        ; return DPH address
  209.     ret
  210. ;
  211. ;    This fake DPH holds the addresses of the actual
  212. ;    DPB.  The CP/M 3.0 DPH is *not* understood
  213. ;    by CP/M 2.2 programs.
  214. ;
  215. dph:    equ    $
  216.     dw    0        ; no translation
  217.     ds    6        ; scratch words
  218.     ds    2        ; directory buffer
  219. dpb:    ds    2        ; DPB
  220.     ds    2        ; CSV
  221.     ds    2        ; ALV
  222. ;
  223. ;    Set track.
  224. ;
  225. settrk:    sbcd    sektrk
  226.     ret
  227. ;
  228. ;    Set dma.
  229. ;
  230. setdma:    sbcd    dmaadr
  231.     ret
  232. ;
  233. ;    Translate sectors.  Sectors are not translated yet.
  234. ;    Wait until we know the physical sector number.
  235. ;    This works fine as long as the program trusts
  236. ;    the BIOS to do the translation.  Some programs
  237. ;    access the XLAT table directly to do their own
  238. ;    translation.  These programs will get the wrong
  239. ;    idea about disk skew but it should cause no
  240. ;    harm.
  241. ;
  242. sectran:mov    l,c        ; return sector in HL
  243.     mov    h,b
  244.     ret
  245. ;
  246. ;    Set sector number.
  247. ;
  248. setsec:    mov    a,c
  249.     sta    seksec
  250.     ret
  251. ;
  252. ;    Read the selected CP/M sector.
  253. ;
  254. read:    mvi    a,1
  255.     sta    readop        ; read operation
  256.     inr    a        ; a=2 (wrual)
  257.     sta    wrtype        ; treat as unalloc
  258.     jmp    alloc        ; perform read
  259. ;
  260. ;    Write the selected CP/M sector.
  261. ;
  262. write:    xra    a
  263.     sta    readop        ; not a read operation
  264.     mov    a,c
  265.     sta    wrtype        ; save write type
  266.     cpi    2        ; unalloc block?
  267.     jrnz    chkuna
  268. ;
  269. ;    Write to first sector of unallocated block.
  270. ;
  271.     lda    bsm        ; get block shift mask
  272.     inr    a        ; adjust value
  273.     sta    unacnt        ; unalloc record count
  274.     lda    sekdsk        ; set up values for
  275.     sta    unadsk        ; writing to an unallocated
  276.     lda    sektrk        ; block
  277.     sta    unatrk
  278.     lda    seksec
  279.     sta    unasec
  280. ;
  281. chkuna:    lda    unacnt        ; any unalloc sectors
  282.     ora    a        ; in this block
  283.     jrz    alloc        ; skip if not
  284.     dcr    a        ; --unacnt
  285.     sta    unacnt
  286.     lda    sekdsk
  287.     lxi    h,unadsk
  288.     cmp    m        ; sekdsk = unadsk ?
  289.     jrnz    alloc        ; skip if not
  290.     lda    sektrk
  291.     cmp    m        ; sektrk = unatrk ?
  292.     jrnz     alloc        ; skip if not
  293.     lda    seksec
  294.     lxi    h,unasec
  295.     cmp    m        ; sektrk = unasec ?
  296.     jrnz    alloc        ; skip if not
  297.     inr    m        ; move to next sector
  298.     mov    a,m
  299.     lxi    h,spt        ; addr of spt
  300.     cmp    m        ; sector > spt ?
  301.     jrc    noovf        ; skip if no overflow
  302.     lhld    unatrk
  303.     inx    h
  304.     shld    unatrk        ; bump track
  305.     xra    a
  306.     sta    unasec        ; reset sector count
  307. noovf:    xra     a
  308.     sta    rsflag        ; don't pre-read
  309.     jr    rwoper        ; perform write
  310. ;
  311. alloc:    xra    a        ; requires pre-read
  312.     sta    unacnt
  313.     inr    a
  314.     sta    rsflag        ; force pre-read
  315. ;
  316. rwoper:    xra    a
  317.     sta    erflag        ; no errors yet
  318.     lda    psh        ; get physical shift factor
  319.     ora     a        ; set flags
  320.     mov    b,a
  321.     lda    seksec        ; logical sector
  322.     lxi    h,hstbuf    ; addr of buffer
  323.     lxi    d,128
  324.     jrz    noblk        ; no blocking
  325.     xchg            ; shuffle registers
  326. shift:    xchg
  327.     rrc
  328.     jrnc    sh1
  329.     dad    d        ; bump buffer address
  330. sh1:    xchg
  331.     dad    h
  332.     ani    07fh        ; zero high bit
  333.     djnz    shift
  334.     xchg            ; HL=buffer addr
  335. noblk:    sta    sekhst
  336.     shld    sekbuf
  337.     lxi    h,hstact    ; buffer active flag
  338.     mov    a,m
  339.     mvi    m,1        ; set buffer active
  340.     ora    a        ; was it already?
  341.     jrz    filhst        ; fill buffer if not
  342.     lda    sekdsk
  343.     lxi    h,hstdsk    ; same disk ?
  344.     cmp    m
  345.     jrnz    nomatch
  346.     lda    sektrk
  347.     lxi    h,hsttrk    ; same track ?
  348.     cmp    m
  349.     jrnz    nomatch
  350.     lda    sekhst        ; same buffer ?
  351.     lxi    h,hstsec
  352.     cmp    m
  353.     jrz    match
  354. ;
  355. nomatch:
  356.     lda    hstwrt        ; buffer changed?
  357.     ora    a
  358.     cnz    writehst    ; clear buffer
  359. ;
  360. filhst:    lda    sekdsk
  361.     sta    hstdsk
  362.     lhld    sektrk
  363.     shld    hsttrk
  364.     lda    sekhst
  365.     sta    hstsec
  366.     lda    rsflag        ; need to read ?
  367.     ora    a
  368.     cnz    readhst        ; yes
  369.     xra    a
  370.     sta    hstwrt        ; no pending write
  371. ;
  372. match:    lhld    dmaadr
  373.     xchg
  374.     lhld    sekbuf
  375.     lda    readop        ; which way to move ?
  376.     ora    a
  377.     jrnz    rwmove        ; skip if read
  378.     mvi    a,1
  379.     sta    hstwrt        ; mark buffer changed
  380.     xchg            ; hl=dma  de=buffer
  381. ;
  382. rwmove:    lxi    b,128        ; byte count
  383.     ldir            ; block move
  384.     lda    wrtype        ; write type
  385.     cpi    1        ; to directory ?
  386.     jrnz    exit        ; done
  387.     lda    erflag        ; check for errors
  388.     ora    a
  389.     jrnz    exit        ; don't write dir if so
  390.     xra    a
  391.     sta    hstwrt        ; show buffer written
  392.     call    writehst    ; write buffer
  393. exit:    lda    erflag
  394.     ret
  395. ;
  396. ;    Disk read.  Call CP/M 3.0 BIOS to fill the buffer
  397. ;     with one physical sector.
  398. ;
  399. readhst:
  400.     call    rw$init        ; init CP/M 3.0 BIOS
  401.     mvi    a,13        ; read function number
  402.     call    xbios        ; read sector
  403.     sta    erflag
  404.     ret
  405. ;
  406. ;    Disk write.  Call CP/M 3.0 BIOS to write one
  407. ;    physical sector from buffer.
  408. ;
  409. writehst:
  410.     call    rw$init        ; init CP/M 3.0 BIOS
  411.     mvi    a,14        ; write function number
  412.     call    xbios        ; write sector
  413.     sta    erflag
  414.     ret
  415. ;
  416. ;    Translate sector.  Set CP/M 3.0 track, sector,
  417. ;    DMA buffer and DMA bank.
  418. ;
  419. rw$init:
  420.     lda    hstsec        ; physical sector number
  421.     mov    l,a
  422.     mvi    h,0
  423.     shld    bcreg        ; sector number in BC
  424.     lhld    xlat        ; address of xlat table
  425.     shld    dereg        ; xlat address in DE
  426.     mvi    a,16        ; sectrn function number
  427.     call    xbios        ; get skewed sector number
  428.     mov    a,l
  429.     sta    actsec        ; actual sector
  430.     shld    bcreg        ; sector number in BC
  431.     mvi    a,11        ; setsec function number
  432.     call    xbios        ; set CP/M 3.0 sector
  433.     lhld    hsttrk        ; physical track number
  434.     shld    bcreg        ; track number in BC
  435.     mvi    a,10        ; settrk function number
  436.     call    xbios
  437.     lxi    h,hstbuf    ; sector buffer
  438.     shld    bcreg        ; buffer address in BC
  439.     mvi    a,12        ; setdma function number
  440.     call    xbios
  441.     mvi    a,1        ; DMA bank number
  442.     sta    areg        ; bank number in A
  443.     mvi    a,28        ; setbnk function number
  444.     call    xbios        ; set DMA bank
  445.     ret
  446. ;
  447. ;    Print message at HL until null.
  448. ;
  449. prmsg:    mov    a,m
  450.     ora     a
  451.     rz
  452.     mov    c,m
  453.     push    h
  454.     call    xconout
  455.     pop    h
  456.     inx    h
  457.     jmp    prmsg
  458. ;
  459. ;    disk i/o buffer
  460. ;
  461. hstbuf:    ds    max$sector$size
  462. ;
  463. ;    variable storage area
  464. ;
  465. sekdsk:    ds    1        ; logical disk number
  466. sektrk:    ds    2        ; logical track number
  467. seksec:    ds    1        ; logical sector number
  468. ;
  469. hstdsk:    ds    1        ; physical disk number
  470. hsttrk:    ds    2        ; physical track number
  471. hstsec:    ds    1        ; physical sector number
  472. ;
  473. actsec:    ds    1        ; skewed physical sector
  474. sekhst:    ds    1        ; temp physical sector
  475. hstact:    ds    1        ; buffer active flag
  476. hstwrt:    ds    1        ; buffer changed flag
  477. ;
  478. unacnt:    ds    1        ; unallocated sector count
  479. unadsk:    ds    1        ; unalloc disk number
  480. unatrk:    ds    2        ; unalloc track number
  481. unasec:    ds    1        ; unalloc sector number
  482. sekbuf:    ds    2        ; logical sector address in buffer
  483. ;
  484. spt:    ds    1        ; cpm sectors per track
  485. xlat:    ds    2        ; xlat address
  486. bsm:    ds    1        ; block shift mask
  487. psh:    ds    1        ; physical shift factor
  488. ;
  489. erflag:    ds    1        ; error reporting
  490. rsflag:    ds    1        ; force sector read
  491. readop:    ds    1        ; 1 if read operation
  492. rwflag:    ds    1        ; physical read flag
  493. wrtype:    ds    1        ; write operation type
  494. dmaadr:    ds    2        ; last dma address
  495. oldaddr:ds    2        ; address of old BIOS
  496. ;
  497.     end
  498.