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 / CPM / CPM3 / BANKSWAP.LBR / BANKSWAP.ASM < prev    next >
Assembly Source File  |  2000-06-30  |  11KB  |  493 lines

  1. ; BANKSWAP.ASM
  2. ; A. S. Woodhull      28 June 83
  3. ; rev     1 July 85    -- minor editing
  4. ;     20 Oct 83
  5. ; This is designed to be run as a subprogram under DDT
  6. ; or SID, in a banked version of CP/M 3.0  The function
  7. ; of BANKSWAP is to copy blocks of memory from other 
  8. ; banks to and from bank 1, using a buffer in the common
  9. ; area.  Normal DDT or SID functions can then be 
  10. ; performed, using the copy of the code in bank 1.  
  11. ; (Of course, you cannot trace through program segments
  12. ; that switch banks or access memory mapped I/O in 
  13. ; another bank.)
  14. ; BANKSWAP must reside in the common area of memory, and
  15. ; a buffer area through which data can be copied must 
  16. ; also be present in the common area.  BANKSWAP is to be
  17. ; assembled as a Resident System Extension (RSX), which
  18. ; will automatically be relocated to the top of the TPA.
  19. ; It is assumed that the common area is large enough to 
  20. ; allow an RSX to fit--if this is not true BANKSWAP will
  21. ; not work in its present form.
  22. ; Because the location of BANKSWAP in memory is not fixed
  23. ; a jump through a fixed location is set up when the BANK-
  24. ; SWAP code is installed.  In this version the  RST 5 vector
  25. ; at 28H is used, but any convenient location on page zero
  26. ; may be used. 
  27. ; Under CP/M 3 direct access of BIOS routines is generally
  28. ; to be avoided by user programs, since BIOS routines may
  29. ; have expectations about which bank is selected when they 
  30. ; are called.  We will, however, do bank switching through
  31. ; the BIOS selmem routine.  For generality we will use the 
  32. ; BIOS vector at location 1.
  33. true:    equ    0ffffh
  34. false:    equ    not true
  35. alone:    equ    false    ;make false if attached to DDT/SID
  36. biosv:    equ    1    ;address of wboot in BIOS found here
  37. selmem:    equ    4eh    ;offset from wboot 
  38. buflen:    equ    100h    ;move block size
  39. ; default parameters
  40. movcnt:    equ    1000h    ;to move 16 pages (4K) at a time
  41. b0dft:    equ    100h    ;start of block in bank 0
  42. b1dft:    equ    100h    ;start of block in bank 1
  43. ; zero page addresses
  44. bdos:    equ    5    ;bdos entry point
  45. rstv:    equ    28h    ;RST 5 used as entry vector
  46. ; BDOS functions used
  47. conin:    equ    1    ;get a char
  48. printf:    equ    9    ;print a string
  49. rdbuf:    equ    10    ;read a line
  50. ; This is standard prefix for a Resident System Extension
  51. ;  see CP/M 3 Programmer's Guide, 1st ed., sec. 4.4, p.168
  52. serial:    db    0,0,0,0,0,0
  53. start:    jmp    install    ;one-time routine
  54. next:    jmp    0    ;altered at installation
  55. prev:    dw    0
  56.     if    alone
  57. rmvflg:    db    0    ;keep this in memory 
  58.     else    
  59. rmvflg:    db    0ffh    ;remove when main program ends
  60.     endif
  61. nonbnk:    db    0    ;banked system
  62.     db    'BANKSWAP'
  63. loader:    db    0
  64.     db    0,0
  65. ; *** note: If BANKSWAP is to be attached directly to SID.COM
  66. ; or DDT.COM then make rmvflg 0ffh to force removal 
  67. bankexam:
  68.     lxi    h,0    ;get stack pointer
  69.     dad    sp    ;...and hold it for return
  70.     shld    holdsp    ;...reset SP to a location
  71.     lxi    sp,locstk    ;...in common memory
  72. ; Main loop--exit by Quit or Remove command
  73. bankex2:
  74.     call    prompt    ;this returns address of sub
  75.     call    doit    ;do subroutine addressed by HL
  76.     jmp    bankex2
  77. prompt:    lxi    d,menu    ;get ready for menu
  78.     lda    quietflag
  79.     ora    a    ;suppress menu?
  80.     jz    prmpt2
  81. prmpt1:    lxi    d,query    ;set for prompt only
  82. prmpt2:    mvi    c,printf
  83.     call    bdos    
  84. ; Get a character
  85.     mvi    c,conin
  86.     call    bdos
  87.     call    crlf
  88. ; make upper case, reject non-alpha
  89.     ani    5fh
  90.     cpi    'A'
  91.     jc    prmpt1    ;ask again if invalid
  92.     cpi    'Z'+1
  93.     jnc    prmpt1    ;ask again if invalid
  94. ; find match in alphtbl
  95.     lxi    b,altblen    ;length of table
  96.     lxi    h,alphtbl+altblen    ;work back
  97. try:    cmp    m
  98.     jz    match
  99.     dcx    h
  100.     dcr    c    ;count down
  101.     jnz    try
  102. ; if c= 0 no match found.  Now form address
  103. match:    lxi    h,addrtbl
  104.     dad    b    ;add offset
  105.     dad    b    ;again, 2 bytes per table entry
  106. ; get the command address
  107.     mov    a,m
  108.     inx    h
  109.     mov    h,m
  110.     mov    l,a
  111.     ret        ;HL has action address
  112. doit:    pchl        ;call here to use action address
  113. getbank:
  114.     lhld    b0start    ;setup addresses
  115.     shld    source
  116.     lhld    b1start
  117.     shld    dest
  118.     lda    length+1    ;low byte ignored
  119.     sta    count
  120. ; page by page take a chunk of bank 0 to buffer, then move
  121. ; to bank 1 destination
  122. get2:    
  123.     di        ;be sure no interrupts
  124.     mvi    a,0
  125.     lhld    selmv
  126.     call    doit
  127.     call    getbuf
  128.     mvi    a,1
  129.     lhld    selmv    ;point to BIOS selmem routine
  130.     call    doit
  131.     ei        ;interrupts safe again
  132.     call    putbuf
  133.     lxi    d,buflen
  134.     lhld    source
  135.     dad    d
  136.     shld    source
  137.     lhld    dest
  138.     dad    d
  139.     shld    dest
  140.     lxi    h,count    ;repeat for required # of pages
  141.     dcr    m
  142.     jnz    get2
  143.     ret
  144. putbank:
  145.     lhld    b1start
  146.     shld    source
  147.     lhld    b0start
  148.     shld    dest
  149.     lda    length+1    ;low byte ignored
  150.     sta    count
  151. ; page by page, move bank 1 data to buffer, then move it 
  152. ; to bank 0
  153. put2:
  154.     call    getbuf
  155.     di        ;be sure no interrupts
  156.     mvi    a,0
  157.     lhld    selmv
  158.     call    doit
  159.     call    putbuf
  160.     mvi    a,1
  161.     lhld    selmv
  162.     call    doit
  163.     ei        ;interrupts safe again
  164.     lxi    d,buflen
  165.     lhld    source
  166.     dad    d
  167.     shld    source
  168.     lhld    dest
  169.     dad    d
  170.     shld    dest
  171.     lxi    h,count
  172.     dcr    m
  173.     jnz    put2
  174.     ret
  175. ; source to buffer
  176. getbuf:
  177.     lhld    source
  178.     lxi    d,buffer
  179.     jmp    pb1
  180. ; buffer to dest
  181. putbuf:
  182.     lhld    dest
  183.     lxi    d,buffer
  184.     xchg
  185. ; common code for getbuf and putbuf
  186. pb1:    lxi    b,buflen
  187. ; move (BC) bytes from (HL) to (DE) (could use BIOS move
  188. ; routine for this)
  189. move:    mov    a,m    
  190.     stax    d
  191.     inx    h
  192.     inx    d
  193.     dcx    b
  194.     mov    a,b
  195.     ora    c
  196.     jnz    move
  197.     ret
  198. ; Go back to SID/DDT
  199. quit:    lxi    d,qmsg    ;say how to get back
  200.     mvi    c,printf
  201.     call    bdos
  202.     lhld    holdsp    ;restore stack pointer
  203.     sphl
  204.     rst    7    ;back to DDT or SID
  205.     if    alone
  206. ; Set for removal on termination of SID or DDT
  207. remove:    lxi    h,rmvflg    ;set the remove flag
  208.     mvi    m,0ffh        ;...in the RSX prefix 
  209.     lxi    h,rstv        ;then wipe out the entry
  210.     mvi    m,0ffh        ;...JMP with an RST 7
  211.     rst    7        ;leave via the debugger
  212.     endif    ;alone
  213. ; Set up addresses for move, also set up length
  214. adset:    lxi    d,b0id    ;tell current bank 0 addr
  215.      mvi    c,printf
  216.     call    bdos
  217.     lhld    b0start    ;get the address
  218.     call    addro    ;and print it
  219.     lxi    h,b0start
  220.     call    update    ;enter hex to (HL)
  221.     lxi    d,b1id    ;do it again for bank 1
  222.      mvi    c,printf
  223.     call    bdos    ;tell
  224.     lhld    b1start
  225.     call    addro
  226.     lxi    h,b1start
  227.     call    update    ;get new address, if any
  228. ; Can fall through from adset or enter directly here to set
  229. ; length of block moved
  230. lnset:    lxi    d,lnmsg    ;tell current length
  231.      mvi    c,printf
  232.     call    bdos
  233.     lhld    length
  234.     call    addro
  235.     lxi    h,length
  236.     call    update    ;offer to change it
  237.     call    crlf
  238.     ret
  239. ; Toggle menu off/on
  240. xpert:    lda    quietflag
  241.     cma            ;toggle
  242.     sta    quietflag
  243.     ret
  244. ; Get here on invalid command
  245. na:    lxi    d,namsg        ;say can't do it
  246.     mvi    c,printf
  247.     call    bdos
  248.     ret
  249. crlf:    push    b
  250.     push    d
  251.     push    h
  252.     push    psw
  253.     lxi    d,crlfstring
  254.     mvi    c,printf
  255.     call    bdos
  256.     pop    psw
  257.     pop    h
  258.     pop    d
  259.     pop    b
  260.     ret
  261. ; get string, do nothing if null, else convert, store at (HL)
  262. update:
  263.     push    h        ;save the location
  264. ; loop back here if input is not valid
  265. upd1:    lxi    h,0        ;initial buffer
  266.     shld    inbuf+1
  267.     lxi    d,chquery    ;say what's up
  268.     mvi    c,printf
  269.     call    bdos
  270.     lxi    d,inbuf
  271.     mvi    c,rdbuf        ;read console until <ret>
  272.     call    bdos
  273.     call    crlf
  274.     lda    inbuf+1        ;get length of hex string
  275.     ora    a        ;check for 0 length input
  276.     jnz    convert
  277. ; null string, go back
  278.     pop    h        ;retrieve value at entry
  279.     ret
  280. ; Convert the hex string in the buffer to binary
  281. convert:
  282.     lxi    h,0    ;start with a zero
  283.     mov    b,a    ;hold length in B
  284.     lxi    d,inbuf+2
  285. conv2:    ldax    d    ;get first (or next) char
  286.     inx    d
  287.     cpi    60h
  288.     jc    conv3
  289.     ani    5fh    ;make lower case if necessary
  290. conv3:    sui    '0'
  291.     jm    upd1    ;must be valid hex, 0..9, A..F
  292.     cpi    0ah
  293.     jc    num    ;jump if a good numeric
  294.     sui    7
  295.     cpi    0ah
  296.     jc    upd1    ;error if not good alpha
  297.     cpi    10h
  298.     jnc    upd1    ;error if not good alpha
  299. num:    dad    h    ;multiply current val by 16
  300.     dad    h
  301.     dad    h
  302.     dad    h
  303.     add    l    ;add new least significant digit
  304.     mov    l,a
  305.     dcr    b    ;countdown the digits
  306.     jnz    conv2
  307.     xchg        ;result to DE
  308.     pop    h    ;HL at entry says where to it
  309.     mov    m,e
  310.     inx    h
  311.     mov    m,d
  312.     ret
  313. ; Print HL as hex
  314. addro:
  315.     push    d
  316.     push    h
  317.     xchg
  318.     lxi    h,hexstr    ;where to build string
  319.     mov    a,d
  320.     call    byte    ;get A as 2 ASCII chars at (HL)
  321.     mov    a,e
  322.     call    byte    ;again, low byte
  323.     lxi    d,hexstr
  324.     mvi    c,printf
  325.     call    bdos    ;print it
  326.     pop    h
  327.     pop    d
  328.     ret
  329. ; Convert byte to hex ASCII chars, put at (HL)
  330. byte:    push    psw
  331.     rar        ;get high nybble
  332.     rar
  333.     rar
  334.     rar
  335.     call    nybble
  336.     pop    psw    ;fall through for low nybble
  337. ; nybble makes 1 char, advances output pointer    
  338. nybble:    ani    0fh
  339.     adi    '0'
  340.     cpi    3ah
  341.     jc    nput
  342.     adi    7
  343. nput:    mov    m,a
  344.     inx    h
  345.     ret
  346. ; Acceptable command inputs go in this table
  347. alphtbl:
  348.     db    0    ;dummy for no match
  349.     db    'A'
  350.     db    'G'
  351.     db    'L'
  352.     db    'P'
  353.     db    'Q'
  354.     if    alone
  355.     db    'R'
  356.     endif    ;alone
  357.     db    'X'
  358. altblen:    equ    $-alphtbl
  359. ; addresses of action routines, same order as alphtabl
  360. addrtbl:
  361.     dw    na    ;not available
  362.     dw    adset    ;address set
  363.     dw    getbank
  364.     dw    lnset    ;length set
  365.     dw    putbank
  366.     dw    quit
  367.     if    alone
  368.     dw    remove
  369.     endif
  370.     dw    xpert    ;expert mode, no menu
  371. menu:    db    'Bankswap 1.0 by A. S. Woodhull 10/20/83',0dh,0ah
  372.     db    'functions available:',0dh,0ah
  373.     db    '    A...set move Addresses',0dh,0ah
  374.     db    '    G...Get alternate bank',0dh,0ah
  375.     db    '    L...set move Length',0dh,0ah
  376.     db    '    P...Put alternate bank',0dh,0ah
  377.     db    '    Q...Quit to SID or DDT',0dh,0ah
  378.     if    alone
  379.     db    '    R...Remove BANKSWAP',0dh,0ah
  380.     endif
  381.     db    '    X...eXpert mode (no menu)',0dh,0ah
  382. query:    db    0dh,0ah,'?? $'
  383. namsg:    db    '...function not available.'
  384. crlfstring:
  385.     db    0dh,0ah,'$'
  386. b0id:    db    'Bank 0 addr: $'
  387. b1id:    db    'Bank 1 addr: $'
  388. lnmsg:    db    'Length is now $'
  389. chquery:
  390.     db    'Change to? (CR to keep): $'
  391. hexstr    ds    4
  392.     db    'H',0dh,0ah,'$'
  393. qmsg:    db    'Re-enter BANKSWAP from DDT or SID by "G28"'
  394.     db    0dh,0ah,'$'
  395. quietflag:
  396.     db    0    ;initialized off
  397. inbuf:    db    8    ;max length of buffer
  398.     ds    9
  399. ; default parameters: alter by Set and Length commands
  400. b0start:    dw    b0dft
  401. b1start:    dw    b1dft    
  402. length:        dw    movcnt     
  403. ; One-time routine, on 1st BDOS call intercepted
  404. install:
  405.     push    b    ;keep everything as it was
  406.     push    d    ;...so BDOS function can be
  407.     push    h    ;...completed
  408.     push    psw
  409. ; set up restart vector for re-entry
  410.     mvi    a,0c3h    ;a JMP instruction
  411.     sta    rstv
  412.     lxi    h,bankexam
  413.     shld    rstv+1
  414. ; set up address of BIOS routine accessed directly
  415.     lhld    biosv        ;find where BIOS is
  416.     lxi    d,selmem    ;...and add offset
  417.     dad    d
  418.     shld    selmv
  419. ; then patch the RSX prefix to prevent reinstallation
  420.     lhld    next+1
  421.     shld    start+1
  422. ; tell 'em we're ready
  423.     mvi    c,printf
  424.     lxi    d,imsg
  425.     call    next
  426.     pop    psw    ;continue with the task that
  427.     pop    h    ;...was so rudely interrupted
  428.     pop    d
  429.     pop    b
  430.     jmp    next
  431. imsg:    db    'BANKSWAP loaded. To access from DDT or '
  432.     db    'SID type "G28"'
  433.     db    0dh,0ah,'$'
  434. ; reuse installation code area for stack space
  435. locstk:
  436. ; uninitialized storage
  437. selmv:    ds    2    ;used for BIOS call to selmem
  438. source:    ds    2    ;for moves to buffer
  439. dest:    ds    2    ;for moves from buffer
  440. count:    ds    1    ;blocks to move
  441. holdsp:    ds    2    ;stack pointer from DDT or SID
  442. buffer:
  443.     ds    buflen
  444.     endinstall:
  445.     push    b    ;keep everything as it was
  446.     p