; Write.asm -- a collection of assembly code display procedures for xm machine
; by Keith Knox last modified September 18, 1979
; by Paul Lam last modified Feb 23, 1981

; write -- procedure to write on the display

.BEXTnewwrite
.BEXTmagCvrt
.BEXTm1
.BEXTm2
.BEXTm3
.BEXTm4
.BEXTBitBlt

.BEXTZ MaxStringHeight, HardCopy, ItalicsBuff, Mag, WindowYmin, WindowXmin
.BEXTZ SavedAC2,CharDef ,CurrentYpos
.BEXTZ DisplayArea, SetBPtr, OnBits, OffBits, SetBMask, MaskTable

.SREL
newwrite:
WRITE
magCvrt:
MagCvrt
m1:
ma1
m2:
ma2
m3:
ma3
m4:
ma4

; write(BBTable, string, font, maxwidth, maxheight,hc,hcwidthvec,rot,magflag,magarea, Yo, type)
; uses BitBlt to write a horizontal string from AL fonts
; It may be possible that this code and the BitBlt code are on separate overlays.
; If so, this procedure must have a stack so that its overlay will not be freed
; when the BitBlt overlay is read into memory.

; BitBlt table should (start on an even address and) be initialized as follows:
; 0--function
// source=block, dest=alt or norm bank, fn=replace,paint,invert,erase
; 1--unused
; 2--dcb!2+TY*((dcb!1)Ź)
; 3--((dcb!1)Ź)
; 4--LX
// updated with width of each character
; 5--0
; 6--0
; 7--0
; 8--0
; 9--1
; 10--0
; 11--0

; if xw=font+char+font!char then BBTable is changed as follows:
; 4--BBTable!4+((xw!0)/2 or 16)
; 5--(xw!1) rshift 8
; 6--(xw!0)/2 or 16
; 7--xw!1 & #377
; 8--xw-(xw!1 & #377)

; Displacements from BBTable
DestBCA = 2
DestBMR = 3
lx=4
disp=5
width=6
height=7
bitmap=8.

; Displacements from stack pointer
string=5
font=6
maxwidth=7
maxheight=8.
hcwidthvec=9.
rot=10.
MagFlag = 11.
MagArea = 12.
YScanstart = 13.
Type=14.
Xstart = 15.
Ystart = 16.
ALHeight = 17.
currXposn = 18.
Lastlx=19.
Displaywidth=20.
BoldFlg=21.

; Lastlx 3
is the last x pos
; width 2
is the width used by BitBlt
; Displaywidth 3
is the actual AL char width

.NREL
Home:
; now time to go home
LDA 0 HcWidth; returns the line width
LDA 2 SavedAC2
JSR @366

WRITE:
STA 3 1 2
JSR @370
30
JSR @367; number arguments is stored in register 0

STA 2 SavedAC2; don’t use BBTable!1 because BitBlt(BBTable) may use it
MOV 2 3
LDA 2 4 2; get BBTable address
LDA 1 lx 2
STA 1 Xstart 3; init xstart
STA 1 Lastlx 3; init Lastlx
LDA 1 DestBCA 2
STA 1 Ystart 3
SUB 1 1
STA 1 MicaPosn; init MicaPosn
STA 1 ScHeight; init ScHeight
LDA 2 SavedAC2

LDA 1 c377; initialize the character mask
STA 1 mask

LDA 0 hcwidthvec 2
STA 0 WidthVector
LDA 0 rot 2
STA 0 rotation

LDA 0 @string 2; initialize the character mask
MOVS 0 0
AND 1 0
SNZ 0 0
JMP Home; if string is emptythen go home
STA 0 charsdone

toploop:
; loop over the # of chars in the string

; get a char and leave it in AC0
LDA 2 SavedAC2; restore stack pointer
LDA 3 string 2; get address of word in string
LDA 0 0 3; get word in string
LDA 1 mask
AND 1 0; mask out the character
SODD 1 1
MOVS 0 0; if necessary, right justify character
INC 3 3
SKEVEN 1 1
STA 3 string 2; if necessary, increment string pointer
COM 1 1
STA 1 mask; switch mask between left and right byte
STA 0 SaveHChar; used by HardCopyCal logic

writechar:
; write out the character in AC0
; get the character descriptor
STA 0 SaveChar
LDA 2 SavedAC2; restore stack pointer
LDA 1 Type 2
movzr 1 1 SZC;Skip on carry generated 2 instructions back
;jmp DoItalics;ifso go make a "sliced" copy of the character definition
MOV 1 1
STA 1 BoldFlg 2; init BoldFlg each time
LDA 1 font 2; get font pointer
lda 0 c2
sub 0 1
#61025; #61025; xmlda -- ac0 ← @ac1
sta 0 ALHeight 2; init font height
sta 0 MaxStringHeight; update string height
LDA 1 font 2; get font pointer
LDA 3 font 2; get font pointer in ac3 to be used later
lda 0 SaveChar
add 0 1
#61025; #61025; xmlda -- ac0 ← @ac1
add 0 1
#61025; #61025; xmlda -- ac0 ← @ac1; AC0 now contains xw!0
sta 0 xw0; ac0 contains xw!0; save it
sta 1 CharBitmapPtr; save character bitmap pointer
inc 1 1
#61025; #61025; xmlda -- ac0 ← @ac1; AC1 now contains xw!1
mov 0 1; AC1 = xw!1
sta 1 xw1

; fill in the height, width, displacement and character bitmap address
LDA 2 4 2; get the BBTable address
LDA 0 c377
COM 0 0
ANDS 1 0
STA 0 disp 2; displacement = xw!1 rshift 8
LDA 0 c377
AND 1 0
STA 0 height 2; height = xw!1 & #377

lda 3 CharBitmapPtr; get character bitmap pointer
SUB 0 3; ac3 has font pointer
STA 3 bitmap 2; bitmap=xw-(xw!1 & #377)
JMP DisplayChar

BitBltProc:
BitBlt
charsdone: 0
mask:
377
CharBitmapPtr: 0
xw0: 0
xw1: 0
c377:
377
c20:
20
SaveChar: 0
SaveHChar: 0
WidthVector: 0
C50: 50.
C1778:
1778.
MicaPosn: 0
ScHeight: 0
HcWidth: 0
rotation:
0
c2:
2
gototoploop: JMP toploop


DisplayChar:
;LDA 0 HardCopy
;MOV 0 0 SZR; always do hardcopy calculations
;JSR HardCopyCal
DoSoftCopy:
; check the width, we may want to quit now
LDA 1 xw0
MOVZR 1 0; AC0 = width
SODD 1 1; if there is an extension
LDA 0 c20; then width is 16
LDA 1 rotation
MOV 1 1 SNR;
JMP DoSC1; no rotation
LDA 1 xw1
MOVS 1 0;
ADD 1 0; ac0 has the width
LDA 1 c377
AND 1 0
DoSC1:
LDA 3 SavedAC2; restore stack pointer
LDA 1 maxwidth 3; don’t go beyond this limit
SNZ 1 1; see when maxwidth becomes zero
JMP alldone; no more to do
SUB 0 1; decrement the maxwidth limit
SN 1 1; is this character too wide?
JMP .+3
ADD 1 0; make width equal to former maxwidth
SUB 1 1; make maxwidth zero
STA 1 maxwidth 3; update maxwidth
STA 0 Displaywidth 3; save the actual AL width
INC 0 0
INC 0 0
LDA 1 c20; check for overflow 16 bits
SUB 0 1
SN 1 1
JMP .+2
LDA 0 c20
STA 0 width 2; store width in BBTable

; check the height, we may want to limit this character
LDA 0 disp 2; number of lines to skip
LDA 1 maxheight 3; get limiting height
SGT 1 0; see if displacement is equal to maxheight
JMP nextchar; don’t bother to display this char
SUB 0 1; subtract the disp from the limiting height
LDA 0 height 2; AC0 = height of character
SGT 1 0; is this character too high?
MOV 1 0; height becomes maxheight
STA 0 height 2; update maxheight
JSR CkMag; check magnify
JSR R180width
; now actually put the character bitmap in the display using BitBlt
DoDisplay:
MOV 2 0
LDA 2 SavedAC2; restore stack pointer
JSRII BitBltProc; BitBlt(BBTable)
1
LDA 2 4 2; get BBTable address

LDA 3 SavedAC2; restore stack pointer
LDA 0 BoldFlg 3
MOVZR 0 0 SZC
JMP MkBold
JSR RZerowidth
; see if there are extensions

nextchar:
LDA 1 xw0; if odd then no extension
MOVZR 1 0; AC0 = pseudocharacter
SODD 1 1
JMP writechar; there is an extension, go back and try again

; check if done with string
DSZ charsdone
JMP gototoploop; end of the loop

alldone:
; now time to go home
LDA 0 HcWidth; returns the line width
LDA 2 SavedAC2
JSR @366

ma1:
MkBold:
sta 0 BoldFlg 3;Bold characters are done by calling Convert again 1 bit to the right
LDA 1 Lastlx 3; get x offset
INC 1 1
STA 1 lx 2; update LX entry in BBTable
JMP DoDisplay

;MicaPosn = MicaPosn + WidthPointer!char
;Xposn = Xstart + MicvaPosn*1778/50
HardCopyCal:
STA 3 HCrtn
LDA 1 WidthVector
LDA 0 SaveHChar; get Char code
ADD 0 1
#61025; #61025; xmlda -- ac0 ← @ac1
LDA 1 MicaPosn
ADD 0 1
STA 1 MicaPosn;MicaPosn updated to the new coordinate
LDA 2 C50;Now scale MicaPosn to required Alto Xposn value
LDA 0 C1778
MOVZR 0 0
MUL
LDA 2 C1778
DIV
MOV# 0,0;noop return for negative result
STA 1 HcWidth
JMP @HCrtn

R180width:
STA 3 R180rtn
;LDA 0 rotation
;
MOV 0 0 SNR;
;
JMP @R180rtn; no rotation
;LDA 3 SavedAC2
;
LDA 0 Displaywidth 3; get actual AL width of character just displayed
;LDA 1 lx 2; get x offset
;
SUB 0 1
;
STA 1 lx 2; update LX entry in BBTable
; check for extension
;
LDA 1 xw0; if odd then no extension
;
MOVZR 1 0; AC0 = pseudocharacter
;
SODD 1 1
;
JMP @R180rtn; there is an extension, go back
; check if hardcopy mode
; always hardcopy for r90 until fonts can be fixed
;LDA 1 HardCopy
;MOV 1 1 SNR
;JMP @R180rtn
;
JSR HardCopyCal; always do hardcopy calculations
;
LDA 3 SavedAC2
;
LDA 1 Xstart 3
;
LDA 0 HcWidth
;
SUB 0 1
;
STA 1 lx 2
JMP @R180rtn


RZerowidth:
STA 3 R0rtn
LDA 3 SavedAC2
LDA 0 rotation
MOV 0 0 SZR
JMP @R0rtn; rotated font; just return
LDA 0 Displaywidth 3; get actual AL width of character just displayed
;
LDA 1 lx 2; get x offset
LDA 1 Lastlx 3; get x offset
ADD 1 0
STA 0 lx 2; update LX entry in BBTable
STA 0 Lastlx 3
; check for extension
LDA 1 xw0; if odd then no extension
MOVZR 1 0; AC0 = pseudocharacter
SODD 1 1
JMP @R0rtn; there is an extension, go back
; check if hardcopy mode
JSR HardCopyCal; always do hardcopy calculations
LDA 1 HardCopy
MOV 1 1 SNR
JMP @R0rtn
LDA 3 SavedAC2
LDA 0 Xstart 3
LDA 1 HcWidth
ADD 0 1
LDA 2 4 3
STA 1 lx 2
STA 1 Lastlx 3
JMP @R0rtn

R0rtn: 0
R180rtn: 0
HCrtn: 0
Nwrds: 36.

CkMag:
STA 3 HCrtn
LDA 0 rotation
MOV 0 0 SZR
JMP @HCrtn; rotated font, no magnify; just return
LDA 3 SavedAC2
LDA 0 MagFlag 3
MOV 0 0 SNR
JMP @HCrtn; no magnify; just return
LDA 0 MagArea 3
MOV 0 0 SNR
JMP @HCrtn; Error; just return
STA 0 DestBCA 2
LDA 1 height 2
ADD 1 0
STA 0 CharDef
INC 1 1
INC 1 1
STA 1 height 2
LDA 0 0 2; get function code
LDA 1 C177776
AND 1 0
STA 0 0 2; change function code to replace (00)
;
SUB 0 0
STA 0 lx 2; lx = 0
STA 0 disp 2; disp = 0
INC 0 0
STA 0 DestBMR 2; DestBMR = 1
LDA 0 C16
STA 0 width 2; width = 16
MOV 2 0
LDA 2 SavedAC2; restore stack pointer
JSRII BitBltProc2; BitBlt(BBTable)
1
ma2:
LDA 2 SavedAC2
LDA 1 Lastlx 2
JSR MagCvrt
LDA 2 SavedAC2
LDA 0 Lastlx 2
LDA 2 4 2
STA 0 lx 2
LDA 0 0 2; get function code
INC 0 0
STA 0 0 2; change function code to paint (01)
JSR RZerowidth
JMP nextchar

BitBltProc2:
BitBlt
C177776:
177776
C16:
16.
; * * * * * * * * * * * * * * * * * * *
;The rest of the code implements a Magnified version of the Convert process

;Exit from MagCvrt -- put here for address range placement
MagDn:

jmp @MagRtn


MagCvrt:

ma3:
sta 3 MagRtn
sta 1 currXposn,2
;let XH = -(CharDef!1 & #377) //number of scanlines to Convert
lda 3 CharDef
lda 3 1,3;CharDef!1
lda 1 C377;CharDef!1 is stIll in AC3
and 3 1
sub 0 0
sub 1 0 SNR;Nothing to do on zero height (space) characters
jmp MagDn
sta 0 XH

;let HD = CharDef!1 rshift 8 //number of scanlines to skip
;let y = (Ystart+HD-WindowYmin)*Mag //not really saved
;SetBPtr = DisplayArea + (y*Nwrds)
lda 0 Con177400;CharDef!1 is stall in AC3
ands 3 0;HD IN AC0
lda 1 YScanstart,2
add 1 0
;
;lda 1 CurrentYpos
;
add 1 0
;
lda 1 WindowYmin
sub 1 0
lda 1 Mag
jsr @343;Multiply
lda 0 Nowrds;y is now in AC1
jsr @343;Multiply
lda 0 DisplayArea
add 0 1
sta 1 SetBPtr

;Yinc = Nwrds*Mag
lda 1 Mag
lda 0 Nowrds
jsr @343;Multiply
sta 1 Yinc

;Ymax = DisplayArea + DisplaySize-Yinc
lda 0 DisplaySize;Yinc is in AC1
sub 1 0
lda 1 DisplayArea
add 1 0
sta 0 Ymax

;OnBits = MaskTable!( Mag+ (BoldFlg? Mag/2, 0) )
lda 0 Mag
movzr 0 1
lda 3 BoldFlg,2
mov 3 3 szr
add 1 0
lda 3 MaskTable
add 0 3
lda 0 0,3
com 0 0
sta 0 OnBits

;let Xpos= (currXposn-WindowXmin)*Mag
lda 0 currXposn,2
lda 1 WindowXmin
sub 1 0
lda 1 Mag
jsr @343; Mul
lda 3 C17
com 3 0;put the constant C177760 in AC0

and 1 0
movl# 0 0 SZC
add 3 0
cycle 14
sta 0 Xpos
; OnBits,,OffBits = (OnBits,,OffBits) rshift (Xposn)
and 1 3
sub 2 2
sub 3 2;leave (-xposn) in AC2
lda 0 OnBits
adc 1 1
jsr MaskSh
sta 0 OnBits
sta 1 OffBits
jmp Yloop

Yinc:
0
Ymax:
0
Xpos:
0
Xptr:
0
XH:
0
Cnt:
0
wd1:
0
DisplaySize:
27432.;**As defined by Sil.defs (Nwrds*ScreenYmax)
C377:
377
Con177400: 177400
C17:
17
Nowrds:
36.;**As defined in Sil.defs
MagRtn: 0

;now set up outside loop
;for sl = -XH to -1 do
Yloop:
lda 2 SetBPtr;check for y to small: ifso skip to next scan line
ma4:
lda 3 DisplayArea
subo# 3 2 SZC
jmp Ydn
lda 3 Ymax;check for y to big: ifso done with conversion
SGT 3 2
jmp MagDn
lda 0 Xpos
sta 0 Xptr
lda 0 OnBits
lda 1 OffBits
sta 1 wd1
lda 1 CharDef
lda 3 XH
add 1 3
lda 1 0,3;lda AC1 with Bits from CharDef!-XH
lda 2 Mag
jmp NxtBit

;now the end of the loop
Ydn:
lda 2 Yinc
lda 3 SetBPtr
add 2 3
sta 3 SetBPtr
isz XH;test for all scan lines converted
jmp Yloop
jmp MagDn

;Now drop into the main bit per scanline loop
;[ //find the next "on"bit in the font and shift the mask bits accordingly
;ShiftCnt = ShiftCnt-Mag
;if FontBits = 0 then break
;let GotBit = (FontBits𘚠) ne 0
;FontBits = FontBits lshift 1
;unless GotBit then loop
;] repeat
;MaskSh(onBits,OffBits,ShiftCnt)
NxtBit:
lda 3 Mag
NxtBitL:
sub 3 2;assumes initial shift cnt in AC3, inc
mov 1,1 SNR;expects Bits to be in AC1
jmp Ydn
movzl 1,1 SNC
jmp NxtBitL
sta 1 SetBMask
lda 1 wd1; restore AC1 with word 1
jsr MaskSh

Bounds:
lda 3 Xptr
movl# 3 3 SZC;skip is Xptr is ls 0
jmp BitDn
lda 2 Nowrds;return is Xptr gr Nwrds
subz 3,2 SBN
jmp Ydn
com# 1 1 SNR;skip if (word 1 ne 0) & (Xptr eq Nwrds)
jmp SetBit
movzr 2 2 SNR
jmp Ydn

SetBit:
lda 3 Mag;find the first memory word address to be modified
sta 3 Cnt
lda 3 SetBPtr
lda 2 Xptr
add 2,3
SetBitL:
lda 2 0,3;get word from screen
and 0 2
adc 0 2;result in AC2 and AC0 is left complemented
sta 2 0,3
com# 1 1 SNR;skip if wd1 is all zero
jmp xitL0
lda 2 1,3;get word from screen
and 1 2
adc 1 2;result in AC2 and AC1 is left complemented
sta 2 1,3
xitL0:
lda 2 Nowrds
add 2 3;increment mem pointer by one scan line
dsz Cnt
jmp SetBitL
BitDn:
sub 2 2
sta 1 wd1
lda 1 SetBMask
jmp NxtBit

;right shift the 32 bit quantity "OnBits,OffBits"
;if OnBits is all zero, then swap words and increment Xptr
;NOTE the content of OnBits,OffBits are to be or’d into the bit map,
;and for convenience of the "OR" algorithm are complements of the bits to be or’d.
MaskSh:
sta 3 Cnt;Cnt is a handy unused register at this point
mov 2 2 SNR;AC2 contains toe quantity to be shifted
jmp@ Cnt;skip if we don’t have any count
shiftL:
movor 0,0;now shift the bit pattern
movr 1,1
com 0,3 SZR;swap words and increment Xptr if all bits are in OffBits
jmp ShiftDn
mov 1 0
com 3 1
isz Xptr
ShiftDn:
inc 2,2 SZR;test for all bits shifted
jmp shiftL
jmp@ Cnt



.END