home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol156 / 1771.lbr / SYSGEN29.ASM < prev    next >
Encoding:
Assembly Source File  |  1985-02-10  |  12.1 KB  |  499 lines

  1. ;
  2. ;    S Y S G E N 2 9 . A S M
  3. ;
  4. ;    This program allows a sysgen to/from system
  5. ;    tracks with 29 sectors per track.
  6. ;
  7. ;    Generated and modified from a disassembly by
  8. ;    Willis E. Howard, III (1983).
  9. ;
  10. ;    Useful constants.
  11. ;    All equate variables in lower case.
  12. ;
  13.     bell    EQU    7    ;ASCII values
  14.     bs    EQU    8
  15.     tab    EQU    9
  16.     lf    EQU    10
  17.     vt    EQU    11
  18.     ff    EQU    12
  19.     cr    EQU    13
  20. ;
  21.     boot    EQU    0    ;Warm boot entry point
  22.     wboot    EQU    1    ;Warm boot vector address
  23.     bdos    EQU    5    ;BDOS entry point
  24.     dfcb    EQU    5CH    ;Default FCB
  25.     dmabuf    EQU    80H    ;Default DMA buffer
  26.     buffer    EQU    900H    ;SYSGEN buffer begin
  27.     maxdsk    EQU    02H    ;Maximum number of drives
  28. ;
  29. ;    Set program origin
  30. ;
  31.     ORG 0100H
  32. ;
  33. ;    Jump over variables and subroutines
  34. ;
  35.     JMP BEGIN
  36. ;
  37.     DB    '                                     '
  38. ;
  39. ;    Total number of system tracks to read/write
  40. TRACKS:
  41.     DB    2H
  42. ;
  43. ;    Total number of sectors per system track
  44. ;    Standard value is 26.  Now set for 29 to
  45. ;    get extended CBIOS.
  46. MXSEC:
  47.     DB    1DH
  48. ;
  49. ;    This is a list of the sectors, from 1 to MXSEC.
  50. ;    The ordering should reflect the desired skew for
  51. ;    your system.  Now set for two.  There is no real
  52. ;    conversion of logical to physical sectors.  This
  53. ;    table just gives the ORDER in which sectors are
  54. ;    read and written.  Unused table space zero filled.
  55. SECLST:
  56.     DB    1H,3H,5H,7H,9H,0BH,0DH,0FH,11H,13H,15H,17H,19H,1BH,1DH
  57.     DB    2H,4H,6H,8H,0AH,0CH,0EH,10H,12H,14H,16H,18H,1AH,1CH
  58.     DB    0H,0H,0H,0H,0H,0H,0H,0H,0H,0H,0H,0H,0H
  59.     DB    0H,0H,0H,0H,0H,0H,0H,0H,0H,0H,0H,0H,0H
  60.     DB    0H,0H,0H,0H,0H,0H,0H,0H,0H
  61. ;
  62. ;    HL = A * 128
  63. ;    This subroutine is used for calculating the offset
  64. ;    of the track buffer for the sector given by A.
  65. MUL128:
  66.     MOV    L,A        ;Put A in HL
  67.     MVI    H,00H
  68.     DAD    H        ;Multiply by 128
  69.     DAD    H
  70.     DAD    H
  71.     DAD    H
  72.     DAD    H
  73.     DAD    H
  74.     DAD    H
  75.     RET            ;Now return
  76. ;
  77. ;    Get a character from the console in upper case.
  78. CONIN:
  79.     MVI    C,01H        ;Read console character code
  80.     CALL    bdos        ;Do it through the BDOS
  81.     CPI    'a'        ;Less than 'a' is OK
  82.     RC
  83.     CPI    '{'        ;Greater than 'z' is OK
  84.     RNC
  85.     ANI    '_'        ;Wipe out LC bit
  86.     RET
  87. ;
  88. ;    Output A to the console
  89. CONOUT:
  90.     MOV    E,A        ;Put the character in E
  91.     MVI    C,02H        ;Write console character code
  92.     CALL    bdos        ;Do it throught the BDOS
  93.     RET
  94. ;
  95. ;    Output a CR, LF
  96. CRLF:
  97.     MVI    A,cr        ;CR out
  98.     CALL    CONOUT
  99.     MVI    A,lf        ;LF out
  100.     CALL    CONOUT
  101.     RET
  102. ;
  103. ;    Output CR, LF and a string
  104. NLOUT:
  105.     PUSH    H
  106.     CALL    CRLF
  107.     POP    H
  108. ;
  109. ;    Output just a string pointed to by HL and
  110. ;    terminated with a zero byte
  111. PSTRING:
  112.     MOV    A,M        ;Get the character
  113.     ORA    A
  114.     RZ            ;End on zero
  115.     PUSH    H
  116.     CALL    CONOUT        ;Else, output it
  117.     POP    H
  118.     INX    H        ;Next address
  119.     JMP    PSTRING        ;And loop
  120. ;
  121. ;    Select the disk given in A
  122. SELDSK:
  123.     MOV    C,A        ;Disk given by C
  124.     LHLD    wboot        ;Vector into BIOS
  125.     LXI    D,018H        ;to select disk routine
  126.     DAD    D
  127.     PCHL
  128. ;
  129. ;    Set the track given in C
  130. SETTRK:
  131.     LHLD    wboot        ;Vector into BIOS
  132.     LXI    D,01BH        ;from wboot address
  133.     DAD    D        ;to set track routine
  134.     PCHL
  135. ;
  136. ;    Set sector given in C
  137. SETSEC:
  138.     LHLD    wboot        ;Get WBOOT address in BIOS
  139.     LXI    D,01EH        ;Offset to set sector address
  140.     DAD    D        ;Calculate it
  141.     PCHL            ;and jump
  142. ;
  143. ;    Set DMA address, given in BC
  144. SETDMA:
  145.     LHLD    wboot        ;Get WBOOT address in BIOS
  146.     LXI    D,021H        ;Offset for set DMA routine
  147.     DAD    D        ;Calculate
  148.     PCHL            ;and execute
  149. ;
  150. ;    Read a sector
  151. READ:
  152.     LHLD    wboot        ;Get WBOOT address in BIOS
  153.     LXI    D,024H        ;Offset for read sector routine
  154.     DAD    D        ;Calculate the address
  155.     PCHL            ;Jump to it
  156. ;
  157. ;    Write a sector
  158. WRITE:
  159.     LHLD    wboot        ;Get WBOOT address in BIOS
  160.     LXI    D,027H        ;Offset for write sector routine
  161.     DAD    D        ;Calculate the address
  162.     PCHL            ;Jump to it
  163. ;
  164. ;    Read a sequential file sector
  165. READSQ:
  166.     MVI    C,014H        ;Command code to read
  167.     JMP    bdos        ;via the BDOS
  168. ;
  169. ;    Open a file to read
  170. OPEN:
  171.     MVI    C,0FH        ;Command code to open
  172.     JMP    bdos        ;a file
  173. ;
  174. ;    This subroutine will read or write the entire
  175. ;    buffer starting at 'buffer', now set at 900H.
  176. ;    TRACKS gives the number of tracks read/written, starting at 0.
  177. ;    MXSEC gives the number of sectors read/written per track.
  178. ;    SECLST determines the order in which sectors are read/written.
  179. RWSYS:
  180.     LXI    H,buffer    ;Get the starting address
  181.     SHLD    POINTER        ;and store it.
  182.     MVI    A,0FFH        ;Get a -1 in track counter so that
  183.     STA    TRKCNT        ;the first increment makes it 0.
  184. ;
  185. ;    Come here to read/write another track.
  186. RWTRK:
  187.     LXI    H,TRKCNT    ;Increment the track counter
  188.     INR    M
  189.     LDA    TRACKS        ;Compare with the total for R/W
  190.     CMP    M
  191.     JZ    FINISH        ;Finish off after total reached.
  192. ;                ;Else begin the R/W track section
  193.     MOV    C,M        ;Get the track counter
  194.     CALL    SETTRK        ;and call the set track routine
  195.     MVI    A,0FFH        ;Get a -1 in the sector counter so that
  196.     STA    SECCNT        ;the first increment makes it 0.
  197. ;
  198. ;    Come here to read/write another sector.
  199. RWSEC:
  200.     LDA    MXSEC        ;Get the maximum sector count.
  201.     LXI    H,SECCNT    ;Increment current sector count
  202.     INR    M        ;and compare
  203.     CMP    M        ;the two.
  204.     JZ    NEWBUF        ;Jump if all sectors are written.
  205. ;
  206.     LXI    H,SECCNT    ;Get the current sector count
  207.     MOV    E,M        ;in DE but we can just
  208.     MVI    D,00H        ;put a 0 in D.
  209.     LXI    H,SECLST    ;This points to the sector list
  210.     MOV    B,M        ;Save the first sector # in B
  211.     DAD    D        ;Calculate the current sector #
  212.     MOV    C,M        ;and save in C.
  213.     PUSH    B        ;Save start and current numbers.
  214.     CALL    SETSEC        ;Set the current sector number.
  215.     POP    B        ;Restore both numbers.
  216.                 ;
  217.     MOV    A,C        ;The difference gives number of sectors
  218.     SUB    B        ;into the current track.
  219.     CALL    MUL128        ;*128 gives the byte count.
  220.                 ;
  221.     XCHG            ;We now add this byte count
  222.     LHLD    POINTER        ;to the base address in memory for the
  223.     DAD    D        ;start of the current track.
  224.     MOV    B,H        ;Put the base address for the current
  225.     MOV    C,L        ;sector in BC and set
  226.     CALL    SETDMA        ;the DMA address.
  227.                 ;
  228.     XRA    A        ;Set a zero in the
  229.     STA    TRYCNT        ;retry count variable
  230. ;
  231. RWTRY:
  232.     LDA    TRYCNT        ;Check for too many errors.
  233.     CPI    10        ;Now set for 10.
  234.     JC    DOIT        ;Jump if OK
  235.                 ;Else there were too many
  236.     LXI    H,RWERR        ;Get string address
  237.     CALL    PSTRING        ;and print error message
  238.     CALL    CONIN        ;Get a console character
  239.     CPI    cr        ;If CR, ignore
  240.     JNZ    EXIT        ;Else, exit now.
  241.                 ;Get here to ignore error
  242.     CALL    CRLF        ;Respond with CR, LF.
  243.     JMP    RWSEC        ;Bravely get next sector.
  244. ;
  245. ;    Perform the read or write
  246. DOIT:
  247.     INR    A        ;Increment retry count
  248.     STA    TRYCNT        ;and save it.
  249.     LDA    RWFLAG        ;Check for read or write
  250.     ORA    A
  251.     JZ    DOREAD        ;Zero means read.
  252. ;
  253.     CALL    WRITE        ;Non-zero means write.
  254.     JMP    NEXT
  255. ;
  256. DOREAD:
  257.     CALL    READ
  258. ;
  259. NEXT:
  260.     ORA    A        ;Check for errors
  261.     JZ    RWSEC        ;Jump on none.
  262. ;
  263.     JMP    RWTRY        ;On error, retry.
  264. ;
  265. ;    Come here after a whole track has been read/written.
  266. ;    This routine calculates the next base address for
  267. ;    new track and stores it.
  268. NEWBUF:
  269.     LDA    MXSEC        ;Get the maximum sector count
  270.     CALL    MUL128        ;in bytes.
  271.     XCHG            ;Put it in DE
  272.     LHLD    POINTER        ;Get previous base address
  273.     DAD    D        ;Add the offset
  274.     SHLD    POINTER        ;and update the poiner
  275.     JMP    RWTRK
  276. ;
  277. ;    Not really much to do to finish up.
  278. FINISH:
  279.     RET
  280. ;
  281. ;    This is the actual start of the SYSGEN program code.
  282. ;    First, the system will be placed in the memory buffer
  283. ;    starting at 900H.  Then, this buffer can be written
  284. ;    to the system tracks of any recognized disk.  There
  285. ;    are three ways for this program to load memory:
  286. ;        1) To read the system tracks of a disk.
  287. ;        2) To read a file, usually CPMxx.COM.
  288. ;        3) To use the copy already in memory.    
  289. BEGIN:
  290.     LXI    SP,STACK    ;Set the stack
  291.     LXI    H,VERSION    ;Sign on with the version number
  292.     CALL    PSTRING
  293.     LDA    dfcb + 1    ;Check for a command line parameter
  294.     CPI    ' '        ;and if none,
  295.     JZ    GET        ;then jump.
  296. ;
  297. ;    This code is not documented in any of the
  298. ;    Dig. Res. manuals that I have seen.  If the
  299. ;    SYSGEN command is followed with a file name as
  300. ;
  301. ;    A>SYSGEN CPM60.COM
  302. ;
  303. ;    then that file is loaded into memory.  This code
  304. ;    thus replaces the step
  305. ;
  306. ;    A>DDT CPM60.COM
  307. ;    DDT VERS 2.2
  308. ;    NEXT  PC
  309. ;    2300 0100
  310. ;    -^C
  311. ;    A>
  312. ;
  313. ;    when you want to sysgen a system different from
  314. ;    that on the system tracks of your system disk.
  315. ;
  316. ;    Note that if you save memory after loading the
  317. ;    system, cold loader and CBIOS with DDT, more
  318. ;    than the 34 pages as stated in the Alteration
  319. ;    Guide may be required.  For 29 sectors/track,
  320. ;    this corresponds to 29+8=37 pages.
  321. ;
  322.     LXI    D,dfcb        ;Get the FCB
  323.     CALL    OPEN        ;and open the file.
  324.     INR    A        ;Check for errors and
  325.     JNZ    FILE        ;jump on none.
  326. ;
  327.     LXI    H,NOFILE    ;Get string address
  328.     CALL    NLOUT        ;and print error message.
  329.     JMP    EXIT        ;Then exit.
  330. ;
  331. ;    First, we have to skip over the junk sectors.
  332. FILE:
  333.     XRA    A        ;Get a zero as
  334.     STA    dfcb+32        ;current record
  335.     MVI    C,010H        ;Count of trash sectors to read.
  336. ;
  337. TRASH:
  338.     PUSH    B        ;Save the count.
  339.     LXI    D,dfcb        ;Get FCB in DE and
  340.     CALL    READSQ        ;read into default buffer.
  341.     POP    B        ;restore count.
  342.     ORA    A        ;On error
  343.     JNZ    SRCERR        ;Report it.
  344. ;
  345.     DCR    C        ;Check count
  346.     JNZ    TRASH        ;and loop till all read.
  347. ;
  348.     LXI    H,buffer    ;Get start address of memory buffer.
  349. ;
  350. ;    Fill the memory buffer from the disk file.
  351. FILLBUF:
  352.     PUSH    H        ;Save buffer address
  353.     MOV    B,H        ;Put it in BC
  354.     MOV    C,L
  355.     CALL    SETDMA        ;and set DMA address
  356.     LXI    D,dfcb
  357.     CALL    READSQ        ;Read next sector
  358.     POP    H        ;Restore pointer
  359.     ORA    A        ;Check for more data
  360.     JNZ    SAVE        ;Jump if all file read.
  361. ;
  362.     LXI    D,80H        ;Sector size
  363.     DAD    D        ;Next address
  364.     JMP    FILLBUF        ;Loop.
  365. ;
  366. ;    Report error in sequential read.
  367. SRCERR:
  368.     LXI    H,SHORT        ;Get string address
  369.     CALL    NLOUT        ;Output the message
  370.     JMP    EXIT        ;Exit
  371. ;
  372. ;    Get the system from disk system tracks.
  373. GET:
  374.     LXI    H,SNAME        ;Ask for source drive.
  375.     CALL    NLOUT
  376.     CALL    CONIN        ;Wait for reply.
  377.     CPI    cr        ;On CR, skip memory load
  378.     JZ    SAVE        ;and jump to save routine
  379. ;
  380.     SUI    'A'        ;Get a valid designator
  381.     CPI    maxdsk        ;Check maximum drive #
  382.     JC    DOGET        ;Jump if OK
  383. ;
  384.     CALL    IVDERR        ;Else, report error
  385.     JMP    GET        ;and try again.
  386. ;
  387. ;    Perform read of system tracks to memory    
  388. DOGET:
  389.     ADI    'A'        ;Make ASCII again.
  390.     STA    SDRIVE        ;Store in the string.
  391.     SUI    'A'        ;Now select the disk
  392.     CALL    SELDSK
  393.     CALL    CRLF        ;Output a CR, LF
  394.     LXI    H,SON        ;and prompt for action.
  395.     CALL    PSTRING
  396.     CALL    CONIN        ;Get reply
  397.     CPI    cr        ;Anything but CR exits
  398.     JNZ    EXIT
  399. ;
  400.     CALL    CRLF        ;Give a CR, LF reply
  401.     XRA    A        ;and set the flag for READ
  402.     STA    RWFLAG
  403.     CALL    RWSYS        ;Read now.
  404.     LXI    H,ALLOK        ;Report read complete.
  405.     CALL    PSTRING        ;Fall through for write.
  406. ;
  407. ;    This section writes memory buffer to disk.
  408. ;    No matter how memory was loaded, once the
  409. ;    program gets here, it can not load memory again.
  410. ;    The system can be written as many times as desired.
  411. SAVE:
  412.     LXI    H,DNAME        ;Prompt for distination
  413.     CALL    NLOUT        ;drive name.
  414.     CALL    CONIN        ;Wait for a reply.
  415.     CPI    cr        ;Anything but CR exits.
  416.     JZ    EXIT
  417. ;
  418.     SUI    'A'        ;Form code.
  419.     CPI    maxdsk        ;Check maximum drive count.
  420.     JC    DOSAVE        ;If OK, do it,
  421.                 ;Else error.
  422.     CALL    IVDERR        ;Report error message
  423.     JMP    SAVE        ;and try again.
  424. ;
  425. ;    Perform save of memory buffer to system tracks.
  426. DOSAVE:
  427.     ADI    'A'        ;Make ASCII again and
  428.     STA    DDRIVE        ;store in string.
  429.     SUI    'A'        ;Back to a code
  430.     CALL    SELDSK        ;and select the disk.
  431.     LXI    H,DON
  432.     CALL    NLOUT        ;Prompt for reply
  433.     CALL    CONIN        ;Wait for reply
  434.     CPI    cr        ;Anything but CR will exit
  435.     JNZ    EXIT
  436. ;
  437.     CALL    CRLF        ;Give a CR,LF response
  438.     LXI    H,RWFLAG    ;Set R/W flag to non-zero
  439.     MVI    M,01H        ;for write.
  440.     CALL    RWSYS        ;DO IT NOW
  441.     LXI    H,ALLOK        ;Report done.
  442.     CALL    PSTRING
  443.     JMP    SAVE        ;Go get another disk to write.
  444. ;
  445. ;    Exit routine
  446. EXIT:
  447.     MVI    A,00H        ;Select disk A:
  448.     CALL    SELDSK
  449.     CALL    CRLF        ;Output CR, LF
  450.     JMP    boot        ;Do a warm boot
  451. ;
  452. ;    Invalid drive error
  453. IVDERR:
  454.     LXI    H,BADNAM    ;Get string address
  455.     CALL    NLOUT        ;Print message
  456.     RET            ;and return.
  457. ;
  458. ;    Strings and variables
  459. VERSION:
  460.     DB    'SYSGEN29 V 2.0',0H
  461. SNAME:
  462.     DB    'Source drive name (or return to skip)',0H
  463. SON:
  464.     DB    'Source on '
  465. SDRIVE:
  466.     DB    0H
  467.     DB    ', then type return',0H
  468. DNAME:
  469.     DB    'Destination drive name (or return to reboot)',0H
  470. DON:
  471.     DB    'Destination on '
  472. DDRIVE:
  473.     DB    0H
  474.     DB    ', then type return',0H
  475. RWERR:
  476.     DB    'Permanent error, type return to ignore',0H
  477. ALLOK:
  478.     DB    'Function complete',0H
  479. BADNAM:
  480.     DB    'Invalid drive name (Use A OR B)       ',0H
  481. NOFILE:
  482.     DB    'No system file on disk',0H
  483. SHORT:
  484.     DB    'System file incomplete',0H,0H
  485. TRKCNT:
  486.     DB    0H        ;Current track count
  487. SECCNT:
  488.     DB    0H        ;Current sector count
  489. RWFLAG:
  490.     DB    0H        ;Indicates a read or write
  491. POINTER:
  492.     DW    0H        ;Points to address to read/write
  493. TRYCNT:
  494.     DB    0H        ;Retry count
  495. ;
  496.     DS    32
  497. STACK:
  498.     END
  499.