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 / SIMTEL / CPMUG / CPMUG038.ARK / BVIOS.ASM < prev    next >
Assembly Source File  |  1985-02-10  |  28KB  |  1,078 lines

  1. ;
  2. ; TITLE        BOB VAN VALZAH'S INPUT/OUTPUT SYSTEM (FOR CP/M)
  3. ;        AND FOR UCSD PASCAL, TOO (AS OF VERSION 8)
  4. ; FILENAME    BVIOS.ASM
  5. ; AUTHOR    ROBERT A. VAN VALZAH  2/22/79
  6. ; LAST REVISOR    R. A. V.   12/15/79
  7. ; REASON    CONDITIONALIZE DIABLO DRIVER
  8. ;
  9. ;
  10. ;
  11. CBIVERS    EQU    14    ;CBIOS VERSION NUMBER
  12. CPMVERS    EQU    14    ;CP/M VERSION NUMBER
  13. ;
  14. ;    CONDITIONAL ASSEMBLY EQUATES
  15. ;
  16. FALSE    EQU    0
  17. TRUE    EQU    NOT FALSE
  18. ;
  19. REL    EQU    FALSE    ;TRUE TO GENERATE RELOCATABLE CODE
  20. MSIZE    EQU    47    ;MEMORY AND CP/M SYSTEM SIZE
  21. NODISKS    EQU    1    ;NUMBER OF PHYSICAL DRIVES IN SYSTEM
  22. ; NOTE:  BACKSPC CAN'T BE TRUE IF PASCAL IS TRUE & NODISKS=1
  23. BACKSPC    EQU    FALSE    ;TRUE TO GENERATE CURSOR BACKUP CODE
  24. PASCAL    EQU    FALSE    ;TRUE TO GENERATE UCSD PASCAL I/O CODE
  25. LCASE    EQU    TRUE     ;TRUE TO GENERATE SOFTWARE LOWER CASE
  26. VDM    EQU    TRUE     ;TRUE TO GENERATE VDM CONSOLE OUT
  27. DIABLO    EQU    FALSE    ;TRUE TO GENERATE DIABLO Hy-Type DRIVER
  28. ;
  29. ;    BASE OF DOS (CCP) LOAD COMPUTATION
  30. ;
  31.     IF    REL
  32. BIAS      EQU    0100H    ;FOR RELOCATION, ASSUME CCP STARTS AT 0
  33.     ENDIF
  34. ;
  35.     IF    NOT REL    ;OTHERWISE USE REAL CCP STARTING ADDR.
  36. BIAS      EQU    (MSIZE-16)*1024+2900H
  37.     ENDIF
  38. ;
  39. ;    OTHER ENTRY CP/M ENTRY POINTS
  40. ;
  41. CPMB    EQU    BIAS    ;CCP START
  42. BDOS    EQU    CPMB+806H    ;BDOS ENTRY POINT
  43. CBIOS    EQU    CPMB+1500H    ;CBIOS START
  44. DOSEND    EQU    CPMB+1700H    ;END OF DOS LOAD +1
  45. ;
  46. ;    COMPUTE NUMBER OF SECTORS TO LOAD
  47. ;
  48. DOSSECT    EQU    (CBIOS-CPMB)/128
  49. ;
  50. ;    DISK I/O PORT NUMBERS
  51. ;
  52. DBASE    EQU    0F8H    ;BASE ADDRESS OF CONTROLLER CARD
  53. COMMAND    EQU    DBASE    ;FD1771 COMMAND OUTPUT
  54. STATUS    EQU    DBASE    ;FD1771 STATUS INPUT
  55. TRACK    EQU    DBASE+1    ;TRACK INPUT/OUTPUT
  56. SECT    EQU    DBASE+2    ;SECTOR OUTPUT
  57. DATA    EQU    DBASE+3    ;DATA INPUT & OUTPUT
  58. WAIT    EQU    DBASE+4    ;DATA SYNCRONIZATION & INTRQ INPUT
  59. CONTROL    EQU    DBASE+4    ;CONTROL OUTPUT
  60. ;
  61. ;    FD1771 COMMANDS
  62. ;
  63. HOMECMD     EQU    0    ;RESTORE (HOME) COMMAND
  64. SEEKCMD     EQU    10H    ;SEEK TRACK COMMAND
  65. READCMD     EQU    88H    ;READ IBM FORMAT
  66. WRITCMD     EQU    0A8H    ;WRITE IN IBM FORMAT
  67. FINTCMD     EQU    0D0H    ;FORCE INTERRUPT
  68. ;
  69. ;    OPTION BITS WITHIN COMMANDS
  70. ;
  71. LOADHEAD EQU    08H    ;LOAD HEAD WHILE SEEKING
  72. RATE     EQU    10B    ;STEP RATE OF 10MS.
  73. ;
  74. ;    VDM EQUATES
  75. ;
  76. SCREEN    EQU    0CC00H    ;STARTING SCREEN ADDRESS
  77. SCRLPT    EQU    0C8H    ;SCROLL PORT
  78. ;
  79. ;
  80. ;    DEFINE CBIOS RAM AREAS
  81. ;
  82. ; NON-INITIALIZED RAM
  83. ; SEE ALSO - AREA PAST JUMP TABLE FOR INITIALIZED RAM
  84. ;
  85.     ORG    4H    ;THIS IS WHERE CP/M STORES THE
  86. DISKNO:    DS    1    ;CURRENTLY LOGGED DRIVE
  87. ;
  88.     ORG    40H    ;SCRATCH AREA FOR CBIOS
  89. IOD    DS    2    ;DMA ADDRESS
  90. ;
  91.     ORG    4CH    ;DIABLO PARAMETER RAM
  92. ;
  93. ;    ram parameter area
  94. ;
  95. linhgt    ds    1    ;line height in increments
  96. chwid    ds    1    ;character width in increments
  97. lpp    ds    1    ;lines per page
  98. ;
  99. ;
  100. ; ROUTINES WITHIN THE CBIOS MAY BE INTERNALLY REFERENCED (CALLED
  101. ; FROM WITHIN THE CBIOS), EXTERNALLY REFERENCED (CALLED BY CP/M)
  102. ; OR BOTH.  ANY ROUTINE WHICH IS EXTERNALLY REFERENCED IS
  103. ; ASSUMED TO CLOBBER ALL REGISTERS.  REGISTER USAGE OF ROUTINES
  104. ; REFERENCED ONLY INTERNALLY IS DECLARED IN THE PRE-ROUTINE
  105. ; COMMENT BLOCK.  ANY REGISTERS NOT MENTIONED ARE PRESERVED.
  106. ;
  107. ;
  108.     ORG    CBIOS    ;ORG TO START OF CBIOS AREA
  109. ;
  110. ; I/O JUMP VECTOR
  111. ; THIS IS WHERE CPM CALLS WHENEVER IT NEEDS
  112. ; TO DO ANY INPUT/OUTPUT OPERATION.
  113. ; USER PROGRAMS MAY USE THESE ENTRY POINTS
  114. ; ALSO, BUT NOTE THAT THE LOCATION OF THIS
  115. ; VECTOR CHANGES WITH THE MEMORY SIZE.
  116. ;
  117.     IF    PASCAL
  118.       JMP    $    ;NOT USED IN PASCAL SYSTEM
  119.       JMP    $    ;HANG IF USER COMES HERE
  120.     ELSE
  121.       JMP    CBOOT    ;FROM COLD START LOADER
  122. WBOOTE:
  123.       JMP    WBOOT    ;WARM BOOT ENTRY
  124.     ENDIF
  125.     JMP    CONST    ;CONSOLE STATUS
  126.             ;REG A = 000H IF NO HCARACTER READY
  127.             ;REG A = 0FFH IF CHARACTER IS READY
  128.     JMP    CONIN    ;CONSOLE CHARACTER IN (TO REG A)
  129.     JMP    CONOUT    ;CONSOLE CHARACTER OUT (FROM REG C)
  130.     JMP    LIST    ;LIST OUT (FROM REG C)
  131.     JMP    PUNCH    ;PUNCH OUT (FROM REG C)
  132.     JMP    READER    ;PAPER TAPE READER IN (TO REG A)
  133.     JMP    HOME    ;MOVE DISK HEAD TO TRACK 00
  134.     JMP    SELDSK    ;SELECT THE DISK GIVEN BY REG C
  135.     JMP    SETTRK    ;SET TRACK ADDRESS (0,...76) FOR I/O
  136.     JMP    SETSEC    ;SET SECTOR ADDRESS (1,...26) FOR I/O
  137.     JMP    SETDMA    ;SET DMA ADDRESS FOR I/O
  138.     JMP    READ    ;READ A SECTOR
  139.     JMP    WRITE    ;WRITE A SECTOR
  140. ;
  141. ; INITIALIZED RAM AREAS
  142. ;
  143. ;***********************NOTE:  THE FOLLOWING BYTES MUST
  144. ;            BE IN ADJACENT RAM LOCATIONS
  145. ;            AND NOT CROSS A 256 BYTE PAGE BOUNDRY
  146. IOT    DS    1    ;TRACK
  147. IOS    DS    1    ;SECTOR
  148. SELREQ    DS    1    ;CURRENT DRIVE SELECT REQUEST
  149. LASTSEL    DB    0    ;LAST DRIVE ACTUALLY SELECTED
  150. DHPOS    DB    1    ;HEAD POSITION TABLE
  151.     DS    NODISKS-1 ;STORAGE FOR DISKS B THRU D
  152.     IF    VDM
  153. CURSOR      DW    SCREEN+3C0H
  154.     ENDIF
  155.     IF    BACKSPC
  156. RUBFLG      DB    0    ;NON ZERO IF RUBOUT WAS LAST CHR TYPED
  157.     ENDIF
  158.     IF    PASCAL
  159. BKCHR      DB    0    ;BREAK CHARACTER, 0 IF EMPTY
  160. FLUSH      DB    0    ;FLUSH OUTPUT IF NON ZERO
  161.     ENDIF
  162.     IF    LCASE
  163. ULTG      DB    0FFH    ;UPPER CASE=0, LOWER CASE OTHERWISE
  164.     ENDIF
  165. ;
  166. ; COLD BOOT
  167. ; EXTERNALLY REFERENCED
  168. ; THIS SECTION IS EXECUTED WHENEVER RESET AND RUN
  169. ; IS PUSHED, AFTER THE COLDSTART LOADER READS IN
  170. ; THE CPM SYSTEM.
  171. ;
  172.     IF    NOT PASCAL
  173. CBOOT:
  174.     LXI    SP,100H    ;SET STACK FOR INITILIZATION
  175.         ;NOTE:  SOME RAM INITIALIZATION HAS BEEN DB'D
  176.         ;INTO THE RAM DEFINITION ABOVE
  177.     if    diablo
  178.       mvi    a,6    ;init diablo character width
  179.       sta    chwid
  180.       mvi    a,8    ;init diablo line height
  181.       sta    linhgt
  182.       mvi    a,66    ;init diablo lines per page
  183.       sta    lpp
  184.     endif
  185.     XRA    A    ;COME UP ON DRIVE A
  186.     STA    DISKNO
  187.     IF    VDM
  188.       OUT    SCRLPT    ;INITIALIZE VDM SCROLL PORT
  189.     ENDIF
  190.     CALL    MSGP    ;PRINT SINGNON MESSAGE
  191.     IF    REL
  192.     DB    '00'    ;A MESSAGE THAT DOESN'T CHANGE WITH
  193.             ;DIFFERENT MEMORY SIZES
  194.     ENDIF
  195.     IF    NOT REL
  196.     DB    '0'+MSIZE/10, '0'+MSIZE MOD 10
  197.     ENDIF
  198.     DB    'K CP/M VERS '
  199.     DB    '0'+CPMVERS/10, '.', '0'+CPMVERS MOD 10
  200.     DB    '-'
  201.     DB    '0'+CBIVERS/10, '.', '0'+CBIVERS MOD 10 + 80H
  202.     JMP    GOCPM    ;SET LO MEM JMPS AND ENTER CP/M
  203. ;
  204. ; WARM BOOT
  205. ; EXTERNALLY REFERENCED
  206. ; READ THE CCP AND BDOS IN TO MEMORY AFTER TRANSIENT EXECUTION
  207. ;
  208. WBOOT:
  209.     LXI    SP,100H    ;SET STACK DURING BOOT
  210.     XRA    A    ;BOOT FROM DRIVE A
  211.     STA    SELREQ
  212.     CALL    HOME    ;BOOT FROM TRACK 0
  213.             ;NEXT SECTOR TO READ - 1 KEPT IN REG D
  214.             ;NUMBER OF SECTORS TO GO IN REG E
  215.     LXI    D,(1 SHL 8) + DOSSECT
  216.     LXI    H,CPMB    ;START LOADING AT BASE OF CCP
  217. BOOTSEC:
  218.     INR    D    ;ADD ONE TO SECTOR NUMBER
  219.     MOV    A,D    ;END OF FIRST TRACK?
  220.     CPI    26+1
  221.     JNZ    SAMTRK    ;NO - STAY ON SAME TRACK
  222.     MVI    D,1    ;YES - RESET SECTOR NUMBER TO 1
  223.     MOV    A,D    ;AND STEP IN TO TRACK 1
  224.     STA    IOT
  225. SAMTRK:
  226.     STA    IOS    ;STORE SECTOR FOR READ
  227.     SHLD    IOD    ;STORE DMA ADDRESS FOR READ
  228.     PUSH    D    ;SAVE SECTOR & COUNT WHILE READING
  229.     CALL    READ    ;READ A SECTOR
  230.     POP    D    ;RESTORE SECTOR & COUNT
  231.     DCR    E    ;DECREMENT COUNT (DONE LOADING?)
  232.     JNZ    BOOTSEC    ;NO - KEEP LOADING
  233.             ;YES - FALL THRU TO BRING UP CP/M
  234. ;
  235. ; DONE WITH LOAD, SO SET UP LOW MEMORY JMP VECTORS AND
  236. ; RESET DMA ADDRESS
  237. ;
  238. GOCPM:
  239.     IF    DIABLO
  240.       CALL    INIT    ;INTIALIZE DIABLO
  241.     ENDIF
  242.     LXI    H,80H    ;SET DEFAULT DMA ADDRESS
  243.     SHLD    IOD
  244.     MVI    L,0    ;NOW REG HL = 0
  245.     MVI    M,JMP    ;PUT 'JMP WBOOTE' AT LOCATION 0
  246.     INX    H
  247.     MVI    M,LOW WBOOTE
  248.     INX    H
  249.     MVI    M,HIGH WBOOTE
  250.     INX    H
  251.     INX    H    ;NOW POINTING TO DISKNO (REG HL = 4)
  252.     MOV    C,M    ;GET LAST LOGGED DISK NUMBER FOR CCP
  253.     INX    H    ;POINT TO BDOS JUMP (REG HL = 5)
  254.     MVI    M,JMP    ;PUT 'JMP BDOS' AT LOCATION 5
  255.     INX    H
  256.     MVI    M,LOW BDOS
  257.     INX    H
  258.     MVI    M,HIGH BDOS
  259.     JMP    CPMB
  260.     ENDIF        ;END OF IF NOT PASCAL CONDITIONAL
  261. ;
  262. ; HOME DISK HEAD TO TRACK 0
  263. ; INTERNALLY AND EXTERNALLY REFERENCED
  264. ;
  265. HOME:
  266.     IF    NODISKS NE 1 ;IF MULTI-DRIVE SYSTEM
  267.       CALL    DO$SEL    ;SELECT CORRECT DRIVE BEFORE HOMING
  268.       MVI    A,RATE    ;ISSUE HOME COMMAND
  269.       CALL    CMD$TY1
  270.             ;IGNORE ERRORS
  271.     ENDIF
  272.     MVI    C,0    ;AND FALL THRU TO SET TRACK
  273.     IF    NODISKS NE 1
  274.       CALL    HPADR    ;RESET HEAD POSITION BYTE FOR DRIVE
  275.       MOV    M,C
  276.     ENDIF
  277. ;
  278. ; SET TRACK NUMBER FOR DISK I/O
  279. ; EXTERNALLY REFERENCED
  280. ; ENTRY    C    TRACK NUMBER (0...76)
  281. ;
  282. SETTRK:
  283.     MVI    L,IOT AND 0FFH
  284.     DB    11H    ;GENERATE LXI D TO SKIP NEXT MVI L
  285. ;
  286. ; SET SECTOR NUMBER FOR DISK I/O
  287. ; EXTERNALLY REFERENCED
  288. ; ENTRY    C    SECTOR NUMBER (1...26)
  289. ;
  290. SETSEC:
  291.     MVI    L,IOS AND 0FFH
  292.     DB    11H    ;GENERATE LXI D TO SKIP NEXT MVI L
  293. ;
  294. ; SET DISK DRIVE NUMBER FOR DISK I/O
  295. ; EXTERNALLY REFERENCED
  296. ; ENTRY    C    DRIVE NUMBER (0...3)=(A...D)
  297. ;
  298. SELDSK:
  299.     MVI    L,SELREQ AND 0FFH
  300.     MVI    H,IOT SHR 8
  301.     MOV    M,C
  302.     RET
  303. ;
  304. ; SET DMA ADDRESS FOR DISK I/O
  305. ; EXTERNALLY REFERENCED
  306. ; ENTRY    BC    DMA ADDRESS (0000H-0FFFFH)
  307. ;
  308. SETDMA:
  309.     MOV    H,B
  310.     MOV    L,C
  311.     SHLD    IOD
  312.     RET
  313. ;
  314. ; WRITE A SECTOR TO DISK
  315. ; EXTERNALLY REFERENCED
  316. ;
  317. WRITE:
  318.     MVI    E,WRITCMD
  319.     DB    1    ;GENERATE LXI B TO SKIP MVI E FOLLOWING
  320. ;
  321. ; READ A SECTOR FROM DISK
  322. ; INTERNALLY AND EXTERNALLY REFERENCED
  323. ; EXIT    HL    (IOD)+128    DMA ADDRESS + 128
  324. ;    B,C,D    CLOBBERED
  325. ;
  326. READ:
  327.     MVI    E,READCMD
  328.     CALL    DO$SEL    ;SELECT CORRECT DRIVE F╧R I/O
  329.     IF    PASCAL
  330.       MVI    A,1    ;READY TO RETURN FAILURE CODE
  331.       RC        ;EXIT IF SELECTED DRIVE NOT READY
  332.     ENDIF
  333. RTRY:            ;RETRY RE-ENTRY POINT
  334.     IF    NODISKS EQ 1
  335.       LDA    IOT    ;GET REQUESTED TRACK
  336.     ELSE
  337.       CALL    HPADR    ;GET ADDRESS OF HEAD POSITION BYTE
  338.       LDA    IOT    ;GET REQUESTED TRACK
  339.       MOV    M,A    ;STORE IT AS NEW HEAD POSITION
  340.     ENDIF
  341.     OUT    DATA    ;SEND REQUESTED TRACK TO 1771
  342.     MVI    A,SEEKCMD+LOADHEAD+RATE
  343.     CALL    CMD$TY1    ;COMMAND DISK TO SEEK REQUESTED TRACK
  344.     JNZ    ERROR    ;ISSUE ERROR IF SEEK FAILED
  345.     LDA    IOS    ;SEND REQUESTED SECTOR TO 1771
  346.     OUT    SECT
  347.     LHLD    IOD    ;GET REQUESTED DMA ADDRESS
  348.     CALL    XFER    ;PERFROM DISK I/O TRANSFER
  349.     IN    STATUS    ;SEE IF SUCCUSSFULL
  350.     ANI  1111$1100B    ;CHECK FOLLOWING BITS X/X/X/X$X/X/X/XB
  351.             ;NOT READY/WRITE PROTECT/WRITE FAULT/
  352.             ;RECORD NOT FOUND$CRC ERROR/LOST DATA//
  353.     RZ        ;YES - RETURN WITH REG A = 0
  354. ERROR:
  355.     PUSH    PSW    ;SAVE ERROR BITS
  356.     CALL    MSGP    ;PRINT FIRST PART OF ERROR MESSAGE
  357.     DB    13, 10, 'Error bits', '='+80H
  358.     POP    PSW    ;GET ERROR BITS BACK
  359.     CALL    PHEX    ;PRINT THEM AS A HEX NUMBER
  360. FOOL:
  361.     CALL    MSGP    ;PRINT REST OF ERROR MESSAGE
  362.     DB    ',Retry or Ignore', '?'+80H
  363.     CALL    CONIN    ;GET USERS RESPONSE
  364.     ANI    5FH    ;CONVERT LOWER TO UPPER CASE
  365.     PUSH    PSW    ;SAVE DURRING ECHO
  366.     MOV    C,A    ;ECHO RESPONSE
  367.     CALL    CONOUT
  368.     POP    PSW    ;GET RESPONSE BACK
  369.     SUI    'I'    ;IGNORE?
  370.     RZ        ;YES - SEND ALL OK FLAG BACK TO CP/M
  371.     CPI    'R'-'I'    ;RETRY?
  372.     JNZ    FOOL    ;NO - RE-ISSUE MESSAGE
  373.     MVI    A,RATE    ;YES - SEEK HOME AND TRY AGAIN
  374.     CALL    CMD$TY1    ;ISSUE HOME COMMAND
  375.     JNZ    ERROR    ;ERROR IN HOMING
  376.     JMP    RTRY    ;NO ERROR - TRY OPERATION AGAIN
  377. ;
  378. ; SEND A TYPE ONE COMMAND TO THE CONTROLLER, WAIT FOR FINISH
  379. ; INTERNALLY REFERENCED
  380. ; EXIT    A    ERROR BITS
  381. ;    ZERO    SET IF SUCCESS
  382. ;
  383. CMD$TY1:
  384.     OUT    COMMAND    ;SEND COMMAND
  385.     IN    WAIT
  386.     IN    STATUS    ;GET ALL STATUS BITS
  387.     ANI  1001$1001B    ;LEAVE ONLY THE FOLLOWING
  388.             ;NOT READY///SEEK ERROR$
  389.             ;CRC ERROR///BUSY
  390.     RET        ;RETURN ERROR BITS TO CALLER
  391. ;
  392. ; SEND COMMAND TO 1771 AND PERFORM DISK I/O TRANSFER
  393. ; HEAD WILL BE LOADED FIRST IF HARDWARE TIMEOUT HAS UNLOADED IT
  394. ; INTERNALLY REFERENCED
  395. ; ENTRY    E    1771 COMMAND
  396. ;    HL    I/O ADDRESS
  397. ; EXIT    E    PRESERVED
  398. ;    HL    I/O ADDRESS+128
  399. ;    A,FLAGS    CLOBBERED
  400. ;
  401. XFER:
  402.     MVI    A,FINTCMD ;INTERRUPT 1771 TO GENERATE STATUS
  403.     OUT    COMMAND
  404.     XTHL
  405.     XTHL
  406.     IN    STATUS    ;GET NEW STATUS
  407.     ANI  0010$0000B    ;TRANSFORM HEAD LOADED STATUS INTO
  408.     XRI  0010$0000B
  409.     RAR        ;HEAD LOAD BIT FOR COMMAND
  410.     RAR
  411.     RAR
  412.     ORA    E    ;OR HEAD LOAD BIT IN WITH COMMAND
  413.     OUT    COMMAND    ;SEND COMMAND TO CONTROLLER
  414.     CPI    WRITCMD    ;SEE IF READING OR WRITING
  415.     JNC    XWLOOP    ;WRITING
  416. XRLOOP:
  417.     IN    WAIT    ;WAIT FOR DATA OR INTRQ
  418.     ORA    A    ;SET POSITIVE IF INTRQ
  419.     RP
  420.     IN    DATA    ;DATA IS READ - GO GET IT
  421.     MOV    M,A    ;LOAD INTO DMA ADDR
  422.     INX    H
  423.     JMP    XRLOOP
  424. XWLOOP:
  425.     IN    WAIT    ;WAIT FOR DRQ OR INTRQ
  426.     ORA    A    ;SET POSITIVE IF INTRQ
  427.     RP
  428.     MOV    A,M    ;GET DATA FOR DISK
  429.     OUT    DATA
  430.     INX    H
  431.     JMP    XWLOOP
  432. ;
  433. ; ACTUALLY PERFORM DRIVE SELECTION
  434. ; INTERNALLY REFERENCED
  435. ; ENTRY    (SELREQ)    DRIVE TO BE SELECTED
  436. ; EXIT    A,C,FLAGS,HL    CLOBBERED
  437. ; IN PASCAL VERSIONS:  AS ABOVE EXCEPT
  438. ; EXIT    CARRY        SET IF DRIVE NOT READY OR NON-EXISTANT
  439. ;
  440. DO$SEL:
  441.     IF    NODISKS EQ 1    ;GENERATE LOGICAL SEL CODE
  442.       LXI    H,SELREQ ;GET REQUEST
  443.       MOV    A,M
  444.       IF    PASCAL
  445.         CPI    1    ;CLEAR CARRY IF DRIVE B THRU D SELECTED
  446.         CMC        ;SET CARRY IF ABOVE
  447.         RC
  448.       ENDIF
  449.       INX    H    ;POINT TO LAST DRIVE SELECTED
  450.       CMP    M    ;IS REQUEST SAME AS LAST SELECTED?
  451.       RZ        ;IF SO - SELECT DOES NOTHING
  452.       MOV    M,A    ;IF NOT - UPDATE LAST SELECTED=REQUEST
  453.       CALL    MSGP    ;GIVE MOUNT MESSAGE
  454.       DB    13, 10, 'MOUNT', ' '+80H
  455.       MVI    A,'A'    ;CONVERT REQUEST TO ASCII DRIVE NAME
  456.       ADD    M
  457.       MOV    C,A    ;PRINT REQUESTED DRIVE NAME
  458.       CALL    CONOUT
  459.       IN    0    ;CLEAR ANY CHAR WHICH MIGHT BE WAITING
  460.             ;GO TO CONIN TO WAIT FOR MOUNTING
  461.     ELSE        ;GENERATE PHYSICAL DRIVE SELECT CODE
  462.       LDA    SELREQ    ;GET DRIVE TO SELECT TO REG A
  463.       CMA        ;COMPLIMENT FOR CONTROL LATCH PORT
  464.       ADD A ! ADD A ! ADD A ! ADD A ;ROTATE INTO POSITION
  465.       ORI    2    ;MAKE IT A DRIVE SELECT COMMAND
  466.       OUT    CONTROL    ;SEND COMMAND TO CARD
  467.       CALL    HPADR    ;TELL 1771 WHERE WE LEFT THE HEAD OF
  468.       MOV    A,M    ;THE NEW DRIVE BEING SELECTED
  469.       OUT    TRACK
  470.       MVI    A,FINTCMD ;INTERRUPT 1771 TO GENERATE STATUS
  471.       OUT    COMMAND
  472.       XTHL        ;WAIT FOR STATUS TO MATERIALIZE
  473.       XTHL
  474.       IN    STATUS    ;GET ALL STATUS BITS
  475.       RAL        ;DRIVE NOT READY BIT INTO CARRY
  476.       RET
  477.     ENDIF
  478. ;
  479. ; READ A CHARACTER FROM CONSOLE
  480. ; INTERNALLY AND EXTERNALLY REFERENCED
  481. ; EXIT    A    CHARACTER READ, PARITY RESET
  482. ;    FLAGS    CLOBBERED
  483. ;
  484. CONIN:
  485.     IF    PASCAL
  486.       XRA    A    ;CLEAR FLUSH OUTPUT FLAG
  487.       STA    FLUSH
  488.       PUSH    H    ;SAVE CALLERS REG HL
  489.       LXI    H,BKCHR    ;SEE IF A GOBBLED CHR IS WAITING
  490.       MOV    A,M
  491.       MVI    M,0    ;RESET IT IF IT WAS
  492.       POP    H    ;RESTORE CALLERS REG HL
  493.       ORA    A    ;RESET Z IF ONE WAS WAITING
  494.       RNZ        ;RETURN GOBBLED CHR
  495. HCONIN:            ;HARD CONSOLE IN ENTRY, BKCHR IS IGNORED
  496.     ENDIF
  497.     IN    1
  498.     RAR
  499.     JNC    CONIN
  500.     IN    0
  501.     ANI  0111$1111B    ;MASK PARITY
  502.     IF    BACKSPC
  503.       CPI    7FH    ;WAS RUBOUT TYPED?
  504.       IF    LCASE
  505.         JNZ    CSTEST    ;NO - CHECK FOR CASE CONVERSION
  506.       ELSE
  507.         RNZ        ;NO - LEAVE FLAG ALONE
  508.       ENDIF
  509.       STA    RUBFLG    ;YES - SET RUBOUT FLAG
  510.     ENDIF
  511.     IF    LCASE
  512. CSTEST:
  513.       MOV    B,A    ;SAVE CHR TYPED IN REG B
  514.       CPI    11H    ;ESCAPED TYPED?
  515.       LDA    ULTG
  516.       JZ    ESCP    ;YES - GO COMPLIMENT FLAG
  517.       ORA    A    ;NO - IS MODE = UPPER?
  518.       MOV    A,B    ;PREPARE TO RETURN CHR IF SO
  519.       RZ        ;MODE IS UPPER
  520.       CPI    'A'    ;IS CHR A LETTER?
  521.       RC        ;NO - SKIP CONVERSION
  522.       CPI    'Z'+1
  523.       RNC        ;STILL NOT A LETTER
  524.       ADI    20H    ;IS A LETTER - CONVERT TO LOWER CASE
  525.     ENDIF
  526.     RET
  527.     IF    LCASE
  528. ESCP:
  529.       CMA        ;COMPLIMENT CASE TOGGLE
  530.       STA    ULTG
  531.       JMP    CONIN
  532.     ENDIF
  533. ;
  534. ; CALCULATE HEAD POSITION BYTE ADDRESS
  535. ; INTERNALLY REFERENCED
  536. ; ENTRY (SELREQ) DESIRED DRIVE NUMBER
  537. ; EXIT    HL    ADDRESS OF HEAD POSITION BYTE FOR DRIVE
  538. ;    A,FLAGS    CLOBBERED
  539. ;
  540.     IF    NODISKS NE 1
  541. HPADR:
  542.       LDA    SELREQ    ;GET REQUESTED DRIVE
  543.       ADI    LOW DHPOS ;ADD TO BASE OF HEAD POSITION TABLE
  544.       MOV    L,A    ;RESULT OF ADD TO REG HL
  545.       MVI    H,HIGH DHPOS
  546.       RET
  547.     ENDIF
  548. ;
  549. ; CHECK CONSOLE INPUT STATUS
  550. ; INTERNALLY AND EXTERNALLY REFERENCED
  551. ; EXIT    A    0FFH IF CHRACTER IS READY, 0H IF NOT READY
  552. ;    FLAGS    CLOBBERED
  553. ;
  554. CONST:
  555.     IF    PASCAL
  556.       LDA    BKCHR    ;IF CONOUT GOBBLED A CHARACTER
  557.       ORA    A    ;RESET ZERO
  558.       MVI    A,0FFH    ;PREPARE TO RETURN READY FLAG
  559.       RNZ        ;SEND READY FLAG FOR GOBBLED CHR
  560. HCONST:            ;HARD CONSOLE STATUS CHECK ENTRY
  561.             ;CONTENTS OF BKCHR IS IGNORED
  562.     ENDIF
  563.     IN    1
  564.     RAR
  565.     SBB    A
  566. PUNCH:            ;DUMMY DEVICE
  567. READER:            ;DUMMY DEVICE
  568.     RET
  569. ;
  570. ; OUTPUT CHARACTER TO LIST DEVICE
  571. ; EXTERNALLY REFERENCED
  572. ; ENTRY    C    CHARACTER
  573. ; EXIT    A,FLAGS    CLOBBERED
  574. ;
  575. LIST:
  576.     IF    PASCAL
  577.       LDA    FLUSH    ;ARE WE FLUSHING OUTPUT?
  578.       ORA    A
  579.       RNZ        ;YES - FLUSH PRINTER TOO
  580.     ENDIF
  581.     ;
  582.     ; YOUR PRINTER DRI╓ER HERE
  583.     ;
  584.     IF    DIABLO
  585.       JMP    PRINT    ;SEND TO DIABLO
  586.     ENDIF
  587. ;
  588. ; IN-LINE MESSAGE PRINTER
  589. ; THE MESSAGE MUST BE TERMINATED BY BIT 7 HIGH ON THE LAST
  590. ; CHARACTER.
  591. ; INTERNALLY REFERENCED
  592. ; ENTRY    STACK TOP    MESSAGE ADDRESS (RETURN ADDRESS)
  593. ; EXIT    C,A,FLAGS    CLOBBERED
  594. ; NOTE:  MODIFYS RETURN ADDRESS AND RETURNS ONE BYTE PAST
  595. ; END OF MESSAGE.
  596. ;
  597. MSGP:
  598.     XTHL        ;GET MESSAGE ADDRESS TO REG HL
  599. MSG1:
  600.     MOV    C,M    ;GET A CHR FROM MESSAGE
  601.     CALL    CONOUT    ;PRINT IT
  602.     MOV    A,M    ;GET CHR BACK
  603.     INX    H    ;POINT TO NEXT
  604.     ORA    A    ;WAS BIT 7 SET ON LAST CHR?
  605.     JP    MSG1    ;YES - KEEP PRINTING
  606.     XTHL        ;NO - PUT RETURN ADDRESS BACK
  607.     RET
  608. ;
  609. ; PRINT TWO HEX DIGITS
  610. ; INTERNALLY REFERENCED ROUTINE
  611. ; ENTRY    A    8-BIT VALUE TO BE PRINTED AS TWO HEX DIGITS
  612. ; EXIT    A,C,FLAGS    CLOBBERED
  613. ;
  614. PHEX:
  615.     PUSH    PSW    ;SAVE LOW NIBBLE
  616.     RAR ! RAR ! RAR ! RAR ;POSITION HIGH NIBBLE FOR PRINT
  617.     CALL    PNIB    ;PRINT HIGH NIBBLE
  618.     POP    PSW    ;GET LOW NIBBLE BACK AND . . 
  619.             ;FALL THRU TO PRINT IT
  620. ;
  621. ; PRINT ONE HEX DIGIT
  622. ; INTERNALLY REFERENCED
  623. ; ENTRY    A B3-B0        NIBBLE TO BE PRINTED AS A HEX DIGIT
  624. ; EXIT    A,C,FLAGS    CLOBBERED
  625. ;
  626. PNIB:
  627.     ANI  0000$1111B    ;LEAVE ONLY LOW NIBBLE
  628.     ADI    90H    ;CAUSE CARRY IF > 9
  629.     DAA
  630.     ADI    40H
  631.     DAA
  632.     MOV    C,A    ;PASS ASCII CHAR TO CONOUT
  633.             ;FALL THRU TO CONOUT
  634. ;
  635. ; OUTPUT A CHARACTER TO CONSOLE
  636. ; INTERNALLY AND EXTERNALLY REFERENCED
  637. ; ENTRY    C    ASCII CHARACTER TO BE SENT
  638. ; EXIT    A,FLAGS    CLOBBERED
  639. ;
  640. CONOUT:
  641.     IF    PASCAL
  642.       LDA    FLUSH    ;IS FLUSH FLAG SET?
  643.       ORA    A    ;RESET Z IF SO
  644.       JNZ    FTEST    ;YES - SKIP OUTPUT OF CHARACTER
  645.     ENDIF
  646.     IF    NOT VDM    ;THEN GENERATE NORMAL CONSOLE OUT
  647.       IF    BACKSPC
  648.         MOV    A,C    ;SET Z IF RUBOUT
  649.         CPI    7FH    ;IGNORE RUBOUTS
  650.         IF    PASCAL
  651.           JZ FTEST ;GO CHECK FOR FLUSH
  652.         ELSE
  653.           RZ
  654.         ENDIF
  655.         LDA    RUBFLG    ;WAS RUBOUT THE LAST CHR INPUT?
  656.         ORA    A
  657.         JZ    CONO1    ;NO - JUST OUTPUT NORMALY
  658.         XRA    A    ;YES - RESET RUBOUT FLAG
  659.         STA    RUBFLG
  660.     ; WE NOW KNOW THAT CP/M IS ECHOING THE DELETED
  661.     ; CHARACTER WHICH WE CAN IGNORE
  662.         MVI    C,8    ;MOVE CURSOR OVER DELETED CHR
  663.         CALL CONO1
  664.         MVI    C,' '    ;OVERWRITE IT WITH A BLANK
  665.         CALL CONO1    ;DELETING IT
  666.         MVI    C,8    ;ADJUST CURSOR TO NEW END OF LINE
  667.             ;FALL THRU TO CONO1
  668.       ENDIF        ;END OF IF BACKSPC CONDITIONAL
  669. CONO1:
  670.       IN    0
  671.       RAR
  672.       RAR
  673.       JNC    CONO1
  674.       MOV    A,C
  675.       OUT    1
  676.     ELSE        ;ELSE OF IF NOT VDM, SO HERE VDM IS T
  677.       MOV    A,C
  678.       ANI  0111$1111B    ;MASK PARITY
  679.       CPI    13    ;IGNORE CARRIAGE RETURNS
  680.       RZ
  681.       IF    BACKSPC
  682.         CPI    7FH    ;IGNORE RUBOUTS
  683.         RZ
  684.       ENDIF
  685.       PUSH    H
  686.       LHLD    CURSOR
  687.       CPI    10    ;LF?
  688.       JZ    NEWLINE
  689.       MOV    M,A
  690.       IF    BACKSPC
  691.         LDA    RUBFLG    ;WAS RUBOUT LAST THING TYPED?
  692.         ORA    A
  693.         JNZ    CURLEFT    ;YES - GO MOVE CURSOR LEFT
  694.       ENDIF
  695.       INX    H
  696.       MOV    A,H
  697.       CPI    SCREEN/256+4
  698.       JNZ    EXIT
  699. NEWLINE:
  700.       MVI    M,' '    ;TURN OFF OLD CURSOR
  701.       PUSH    D
  702.       LXI    H,SCREEN
  703.       LXI    D,SCREEN+40H
  704. BLOCKMOVE:
  705.       LDAX    D
  706.       MOV    M,A
  707.       INX    D
  708.       INX    H
  709.       MOV    A,D
  710.       CPI    SCREEN/256+4
  711.       JNZ    BLOCKMOVE
  712.       PUSH    H
  713. BLNK:
  714.       MVI    M,' '
  715.       INX    H
  716.       MOV    A,H
  717.       CPI    SCREEN/256+4
  718.       JNZ    BLNK
  719.       POP    H
  720.       POP    D
  721. EXIT:
  722.       MVI    M,' '+80H
  723.       SHLD    CURSOR
  724.       POP    H
  725.     ENDIF        ;END OF IF NOT VDM CONDITIONAL
  726. ;
  727.     IF    PASCAL
  728. FTEST:
  729.       CALL    HCONST    ;SEE IF CHR IS WAITING
  730.       RZ        ;NO - JUST EXIT FROM CONOUT
  731.       CALL    HCONIN    ;YES - GO GET IT
  732.       CPI    'S'-40H    ;CONTROL S?
  733.       JZ    CONIN    ;YES - GO WAIT FOR ANOTHER KEY TO CONT
  734.       CPI    'F'-40H    ;CONTROL F?
  735.       JZ    CNTLF    ;YES - GO COMPLIMENT FLUSH FLAG
  736.       STA    BKCHR    ;NO - STORE IT AS THE BREAK CHARACTER
  737.       RET
  738. CNTLF:
  739.       LDA    FLUSH    ;GET CURRENT FLUSH FLAG
  740.       CMA        ;COMPLIMENT
  741.       STA    FLUSH    ;WRITE IT BACK
  742.       RET
  743.     ELSE        ;NOT PASCAL I/O
  744.       RET
  745.     ENDIF        ;END OF IF PASCAL CONDITIONAL
  746. ;
  747.     IF    VDM AND BACKSPC ;GENERATE VDM CURSOR LEFT CODE
  748. CURLEFT:
  749.       XRA    A    ;RESET RUBOUT FLAG
  750.       STA    RUBFLG
  751.       MVI    M,' '    ;BLANK EXISTING CHARACTER
  752.       DCX    H    ;BACK UP TO THE LEFT
  753.       JMP    EXIT    ;TURN ON NEW CURSOR & EXIT
  754.     ENDIF        ;END OF IF VDM AND BACKSPC CONDITIONAL
  755.     IF    DIABLO
  756. ;
  757. ;
  758. ; TITLE        BI-DIRECTIONAL DIABLO PRINTER DRIVER
  759. ; FILENAME    BIDI.LIB
  760. ; AUTHOR    Robert A. Van Valzah   9/30/79
  761. ; LAST REVISOR    R.A.V.  11/10/79
  762. ; REASON    byte squeezing
  763. ;
  764. ; plan of attack:
  765. ; ===============
  766. ; characters come in one at a time and are stored into
  767. ; a buffer until a line feed comes in.  at this point,
  768. ; the line in the buffer is analized and a decision is
  769. ; made to print it forward or backward so as to mininmize
  770. ; the head movement.
  771. ;
  772. ; the gory details:
  773. ; =================
  774. ; characters which are printable are just stored in the
  775. ; buffer.  blanks, on the other hand, are accumulated
  776. ; and the number of blanks to move is stored with a bias
  777. ; of 80h.  the first byte of the buffer is an exception:
  778. ; it is initialized to 0h and is used to accumulate the
  779. ; number of spaces between the left margin and the first
  780. ; printable character (this is the location leolpos).
  781. ; the position of the rightmost printable character is
  782. ; keep track of as characters come in the location reolpos.
  783. ;
  784. ; as the head is moved across the page, its position is
  785. ; recorded in hpos.  this information is used in
  786. ; conjunction with leolpos and reolpos to determine if
  787. ; printing forward or backward will cause the shortest
  788. ; printhead movement.  if the printhead is currently to
  789. ; the left of the centerpoint of the line, then it is
  790. ; shortest to move to the left end and start printing.
  791. ; otherwise, it is shortest to move to the right end
  792. ; and print backward.  if the printhead is exactly at
  793. ; the midpoint, the line is printed backward so as to
  794. ; leave the printhead as close to the left margin
  795. ; as possible.
  796. ;
  797. ;
  798. ;    port i/o number equates
  799. ;
  800. base    equ    0f4h
  801. datal    equ    base
  802. datah    equ    base+1
  803. cmand    equ    base+2
  804. stats    equ    base
  805. ;
  806. ;    print formatting equates
  807. ;
  808. ncols    equ    120    ;max number of cols/line (must be <=126)
  809. ;
  810. ;    command bits
  811. ;
  812. restr    equ    1    ;restore carriage
  813. chstb    equ    2    ;character strobe
  814. xstb    equ    4    ;carriage strobe
  815. ystb    equ    8    ;paper feed strobe
  816. selpr    equ    10h    ;select printer
  817. selry    equ    20h    ;select ready
  818. rblft    equ    40h    ;ribbon lift
  819. ;
  820. ;    status bits
  821. ;
  822. chrdy    equ    8    ;character ready
  823. xrdy    equ    10h    ;carriage ready
  824. yrdy    equ    20h    ;paper feed ready
  825. ;
  826. ;
  827. ; print character in reg c
  828. ;
  829. print:
  830.     mov    a,c    ;get char to print to reg a
  831.     ani    7fh    ;strip parity
  832.     mov    c,a
  833.     lhld    nbufad    ;and pointer to next buffer address
  834.     cpi    13    ;test for special characters
  835.     rz        ;ignore carriage return
  836.     cpi    10
  837.     jz    plf    ;line feed
  838.     cpi    12
  839.     jz    pff    ;form feed
  840.     inr    m    ;assume a space
  841.     cpi    ' '
  842.     rz        ;was a space, all done
  843.     dcr    m    ;un-do assumption
  844.     rc        ;was some other control char, ignore
  845.     ;must be a printable character
  846.     mov    a,l    ;see if buffer is about overflow
  847.     cpi    low(buf+ncols-2)
  848.     rz
  849.     cpi    low(buf) ;see if this is first character
  850.     mov    a,m    ;get amt to move before printing
  851.     jz    gotamt    ;jump if first character
  852.     cpi    81h
  853.     jz    noblank    ;no blanks between last & this char
  854.     sui    80h    ;subtract flag value
  855. gotamt:    ;amount to move in reg a
  856.     inx    h    ;move over number of blanks
  857.     db    11h    ;lxi trick to skip following mvi a
  858. noblank:
  859.     mvi    a,1    ;like one blank between character
  860.     mov    m,c    ;store the character comming in
  861.     inx    h    ;point to next buffer location
  862.     mvi    m,81h    ;init to one blank to next char
  863.     shld    nbufad    ;update buffer pointer
  864.     lxi    h,reolpos ;update right end of line position
  865.     add    m
  866.     mov    m,a
  867.     ret
  868. ;
  869. ; print line feed
  870. ;
  871. plf:
  872.     mov    a,l    ;see if nbufad = buf
  873.     cpi    low(buf) ;if = then blank line
  874.     jz    lfend    ;=, so don't print anything
  875.     lda    leolpos    ;get left end of line position
  876.     mov    b,a    ;save it in reg b
  877.     lda    reolpos    ;get right end of line position
  878.     add    b    ;add leolpos to reolpos
  879.     rar        ;divide by two to find midpoint
  880.     mov    b,a    ;save line center point in reg b
  881.     lda    hpos    ;get current head position
  882.     sub    b    ;hpos-(leolpos+reolpos)/2
  883.     jc    forward    ;middle > hpos
  884. ;
  885. ; print the buffer backward
  886. ;
  887. backward:
  888.     mvi    a,80h    ;put end of buffer marker at left end
  889.     sta    buf
  890.     lda    reolpos    ;get absolute position of right eol
  891.     lxi    h,hpos    ;compute amount to move to get there
  892.     sub    m    ;reolpos-hpos
  893.     lhld    nbufad    ;get right most character to print
  894.     dcx    h
  895. bkwd1:
  896.     ;signed distance to move is now in reg a
  897.     call    movprt    ;move as needed and print a character
  898.     dcx    h    ;point to movement amount
  899.     mov    a,m    ;amount to move to reg a
  900.     sui    80h    ;test for eob mark
  901.     jz    lfend    ;hit end of line
  902.     dcx    h    ;assume this is a movement
  903.     cma        ;two's comp for leftward movement
  904.     inr    a
  905.     jnc    bkwd1    ;it was, reg a has amount to move
  906.     inx    h    ;it wasn't, fix buffer pointer
  907.     mvi    a,0ffh    ;move one space to the left
  908.     jmp    bkwd1
  909. ;
  910. ; print buffer forwards
  911. ;
  912. forward:
  913.     mvi    m,80h    ;put in eob mark (also ignores trailing blanks)
  914.     lxi    h,buf    ;pointer into buffer
  915.     mov    a,m    ;absolute pos of leftmost char to reg a
  916.     inx    h    ;point to first printable character
  917.     push    h    ;save buffer pointer
  918.     lxi    h,hpos    ;compute amount to move to get to leolpos
  919.     sub    m    ;leolpos-hpos
  920.     pop    h    ;restore buffer pointer
  921. fwd1:
  922.     ;signed distance to move is now in reg a
  923.     call    movprt    ;move and print a character
  924.     inx    h    ;point to next character
  925.     mov    a,m    ;get it
  926.     sui    80h    ;test for end of line
  927.     jz    lfend    ;hit end of line
  928.     inx    h    ;point to character
  929.     jnc    fwd1    ;was a movement, reg a has distance
  930.     dcx    h    ;was a character, backup pointer
  931.     mvi    a,1    ;and set amount to move to 1
  932.     jmp    fwd1    ;go print next character
  933. ;
  934. ; common finish up routine for print line feed
  935. ;
  936. lfend:
  937.     lxi    h,lfstodo ;add one to line feeds to do before
  938.     inr    m    ;printing next line
  939.     jmp    init1    ;reset pointers
  940. ;
  941. ; print a form feed
  942. ;
  943. pff:
  944.     lda    lpp    ;get lines per page
  945.     lxi    h,lonp    ;subtract lines printed on this page
  946.     sub    m    ;leaving lines left on this page
  947.     sta    lfstodo    ;which is the number of lfs to do
  948.     ret
  949. ;
  950. ; move the number of character positions in reg a (taken as a
  951. ; signed number, + to the right, - to the left) and
  952. ; print the character pointed to by reg hl.
  953. ;
  954. movprt:
  955.     mov    c,m    ;get character to print
  956.     push    h    ;save while printing
  957.     mov    e,a    ;save amount to move in reg e
  958. movr:
  959.     in    stats    ;wait for all movement to stop
  960.     ani    chrdy+xrdy+yrdy
  961.     jnz    movr
  962.     lxi    h,hpos    ;update the head position byte
  963.     mov    a,e
  964.     add    m    ;add amount we are moving
  965.     mov    m,a
  966.     mvi    b,xstb    ;ready x strobe for movstb
  967.     lda    chwid    ;load up character muliplicaton factor
  968.     call    movstb    ;send necessary x movement
  969.     lda    lpp    ;lines per page to reg b
  970.     mov    b,a
  971.     lxi    h,lfstodo ;number of pending line feeds
  972.     mov    a,m    ;skip movement if zero
  973.     ora    a
  974.     jz    noymov    ;no y movement
  975.     mov    e,a    ;movement to reg e for movstb
  976.     mvi    m,0    ;there will be none to do now
  977.     lxi    h,lonp    ;keep track of line on page
  978.     add    m
  979.     mov    m,a
  980.     sub    b    ;see if started new page
  981.     jc    samepage ;nope
  982.     mov    m,a    ;yes - take lonp mod lpp
  983. samepage:
  984.     lda    linhgt    ;load up line multiplicaton factor
  985.     mvi    b,ystb    ;ready y strobe for movstb
  986.     call    movstb    ;send necessary y movement
  987. noymov:
  988.     mov    e,c    ;send character
  989.     mvi    b,chstb    ;send character strobe
  990.     mvi    a,1    ;dummy multiplication factor
  991.     call    movstb
  992.     pop    h
  993.     ret
  994. ;
  995. ; move the signed amount in reg e using value in reg a as
  996. ; a mulitplication factor to get the number of increments
  997. ; then send strobe in reg b.
  998. ;
  999. movstb:
  1000.     push    psw    ;save multiplication factor
  1001.     mov    a,e    ;form a 16 bit amount to move in reg de
  1002.     ral        ;sign of movement into carry
  1003.     sbb    a    ;generate sign extention
  1004.     mov    d,a    ;16-bit signed movement now in reg de
  1005.     pop    psw    ;get multiplication factor
  1006.     lxi    h,0    ;initialize product
  1007. mulbyw:            ;multiply
  1008.     dad    d
  1009.     dcr    a
  1010.     jnz    mulbyw    ;keep multiplying
  1011.     mov    a,h    ;is this leftward movement?
  1012.     ora    a
  1013.     jp    posmov    ;no - distance is ok
  1014.     xra    a    ;yes - negate distance
  1015.     sub    l    ;reg a = 0 - low order
  1016.     mov    l,a    ;which is low order compliment
  1017.     sbb    h    ;now subtract out high order and
  1018.     sub    l    ;subtract out excess low order
  1019.     ;complimented distance now in reg a and reg l
  1020.     ori    4    ;and set negative motion bit
  1021. posmov:
  1022.     cma        ;high order data is active low
  1023.     out    datah    ;send high order data
  1024.     mov    a,l    ;get low order data
  1025.     cma        ;it too is active low
  1026.     out    datal    ;send low  order data
  1027.             ;fall thru to strobe
  1028. ;
  1029. ; pulse strobe in reg b
  1030. ;
  1031. strobe:
  1032.     xra    a    ;delay a while for data set-up time
  1033. dlay:
  1034.     dcr    a
  1035.     jnz    dlay
  1036.     mvi    a,0ffh-selpr-rblft-selry
  1037.     push    psw    ;save bits which are allways high
  1038.     sub    b    ;lower appropriate strobe bit
  1039.     out    cmand    ;send strobe bit low
  1040.     pop    psw    ;and send it high
  1041.     out    cmand
  1042.     ret
  1043. ;
  1044. ; init for printing
  1045. ;
  1046. init:
  1047.     mvi    b,restr    ;pulse restore line to
  1048.     call    strobe    ;reset printer
  1049.     xra    a    ;set software head position to zero
  1050.     sta    hpos
  1051.     sta    lonp    ;reset line counter to top of page
  1052.     sta    lfstodo    ;zero out number of line feeds to do
  1053. init1:    ;empty buffer entry point
  1054.     xra    a    ;reset right end of line position
  1055.     sta    reolpos
  1056.     lxi    h,buf    ;next buffer address pointer
  1057.     shld    nbufad
  1058.     mov    m,a    ;inits left end of line position
  1059.     ret
  1060. ;
  1061. ;    ram areas
  1062. ;
  1063. lonp    ds    1    ;current line on page, 0 = first line
  1064. lfstodo    ds    1    ;line feeds to do before printing
  1065. hpos    ds    1
  1066. reolpos    ds    1
  1067. nbufad    ds    2
  1068. buf:
  1069. leolpos:        ;address of byte containing left eol
  1070.     ds    1
  1071. lmostch:        ;address of left most character
  1072.     ds    ncols
  1073. ;
  1074.     ENDIF        ;END OF IF DIABLO
  1075. ;
  1076.     END
  1077.