-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathprint42.bas
More file actions
549 lines (484 loc) · 16.5 KB
/
print42.bas
File metadata and controls
549 lines (484 loc) · 16.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
' vim:ts=4:et:
#ifndef __PRINT42__
#define __PRINT42__
' --------------------------------------------------
' A PRINT Routine with 42 COLUMNS!
'
' Contributed by Britlion
' --------------------------------------------------
#pragma push(case_insensitive)
#pragma case_insensitive = TRUE
SUB printat42 (y as uByte, x as uByte)
POKE @printAt42Coords,x
POKE @printAt42Coords+1,y
END SUB
SUB print42(characters$ as string)
asm
PROC
LD A, H
OR L
JP Z, print42end
LD C,(HL)
INC HL
LD B,(HL) ; all told, LD BC with the length of the string.
LD A, C
OR B
JP Z, print42end ; Is the length of the string 0? If so, quit.
INC HL ;Puts HL to the first real character in the string.
LOCAL examineChar
examineChar:
LD A,(HL) ; Grab the character at our pointer position
CP 165 ; Too high to print?
JR NC, nextChar ; Then we go to the next
CP 144
JR NC, prn ; char is a UDG
CP 128
JR NC, nextChar ; char is a block graphic
CP 22 ; Is this an AT?
JR NZ, isNewline ; If not jump over the AT routine to isNewline
LOCAL isAt
isAt:
EX DE,HL ; Get DE to hold HL for a moment
;;AND A ; Plays with the flags. One of the things it does is reset Carry.
;;LD HL,00002
;;SBC HL,BC ; Subtract length of string from HL.
LD HL, -2
ADD HL, BC
EX DE,HL ; Get HL back from DE
JP NC, print42end ; If the result WASN'T negative, return. (We need AT to have parameters to make sense)
INC HL ; Onto our Y co-ordinate
LD D,(HL) ; Put it in D
DEC BC ; and move our string remaining counter down one
INC HL ; Onto our X co-ordinate
LD E,(HL) ; Put the next one in E
DEC BC ; and move our string remaining counter down one
ld (xycoords), de
JR nextChar
LOCAL isNewline
isNewline:
CP 13 ; Is this character a newline?
JR NZ, checkdel ; If not, jump forward
LOCAL newline
newline:
ld de, (xycoords)
CALL nxtline ; move to next line
ld (xycoords), de
JR nextChar
LOCAL checkdel
checkdel:
CP 8
JR NZ, checkvalid
ld de, (xycoords)
dec de
ld (xycoords), de
ld a, 41
cp e
JR NC, nextChar
ld e, a
ld (xycoords), de
ld a, 23
cp d
JR NC, nextChar
ld d, a
ld (xycoords), de
JR nextChar
LOCAL checkvalid
checkvalid:
CP 31 ; Is character <31?
JR C, nextChar ; If not go to next character
LOCAL prn
prn:
PUSH HL ; Save our position
PUSH BC ; Save our countdown of chars left
CALL printachar ; Go print a character
POP BC ; Recover our count
POP HL ; Recover our position
LOCAL nextChar
nextChar:
INC HL ; Move to the next position
DEC BC ; count off a character
LD A,B
OR C ; Did we hit the end of our string? (BC=0?)
JR NZ, examineChar ; If not, we need to go look at the next character.
JP print42end ; End the print routine
; This routine forms the new 6-bit wide characters and
; alters the colours to match the text. The y,x co-ordinates and eight
; bytes of workspace are located at the end of this chunk.
; it starts with the character ascii code in the accumulator
LOCAL printachar
printachar:
EXX
PUSH HL ; Store H'L' where we can get it.
EXX
CP 144
jr nc,printudg
ld c, a ; Put a copy of the character in C
ld h, 0
ld l, a ; Put the Character in HL
ld de, whichcolumn-32 ; the character is at least 32, so space = 0th entry.
add hl, de ; HL -> table entry for char.
ld a, (hl) ; Load our column slice data from the table.
cp 32 ; Is it less than 32?
jr nc, calcChar ; If so, go to the calculated character subroutine
; This is the special case 'we defined the character in the table' option
ld de, characters ; Point DE at our table
ld l, a ; Put our character number from our table lookup that's in HL in a
call mult8 ; multiplies L by 8 and adds in DE [so HL points at our table entry]
ld b, h
ld c, l ; Copy our character data address into BC
jr printdata ; We have our data source, so we print it.
LOCAL printudg
printudg
sub 144 ; get the udg offset
ld hl,$5C7B ; examine system variables for udg address
ld e,(hl) ; lsb for udg address
inc hl
ld d,(hl) ; mbs for udg address
ld l,a ; character offset for udg
call mult8 ; multiplies L by 8 and adds in DE [so HL points at our table entry]
ld b, h
ld c, l ; Copy our character data address into BC
jr printdata ; We have our data source, so we print it.
LOCAL calcChar
calcChar: ; this is the calculate from the ROM data option
; a holds the column kill data
ld de, 15360 ; Character set-256. We could use CHARS here, maybe; but might not work with a redefiend character set.
ld l, c ; Get our character back from C
call mult8 ; Multiply l by 8 and add to DE. (HL points at the ROM data for our character now)
ld de, workspace ; Point DE at our 8 byte workspace.
push de ; Save it
exx ;
ld c, a ; Put our kill column in C'
cpl ; Invert
ld b, a ; Put the inverse in B'
exx ;
ld b, 8 ; 8 bytes to a character loop counter
LOCAL loop1
loop1:
ld a, (hl) ; Load a byte of character data
inc hl ; point at the next byte
exx ;
ld e, a ; Put it in e'
and c ; keep the left column block we're using
ld d, a ; and put it in d'
ld a, e ; grab our original back
rla ; shift it left (which pushes out our unwanted column)
and b ; keep just the right block
or d ; mix with the left block
exx ;
ld (de), a ; put it into our workspace
inc de ; next workspace byte
djnz loop1 ; go round for our other bytes
pop bc ; Recover a pointer to our workspace.
LOCAL printdata
printdata:
call testcoords ; check our position, and wrap around if necessary. [returns with d=y,e=x]
inc e ; Bump along to next co-ordinate
ld (xycoords), de ; Store our coordinates for the next character
dec e ; Bump back to our current one
ld a, e ; get x
sla a ; Shift Left Arithmetic - *2
ld l, a ; put x*2 into L
sla a ; make it x*4
add a, l ; (x*2)+(x*4)=6x
ld l, a ; put 6x into L [Since we're in a 6 pixel font, L now contains the # of first pixel we're interested in]
srl a ; divide by 2
srl a ; divide by another 2 (/4)
srl a ; divide by another 2 (/8)
ld e, a ; Put the result in e (Since the screen has 8 pixel bytes, pixel/8 = which char pos along our first pixel is in)
ld a, l ; Grab our pixel number again
and 7 ; And do mod 8 [So now we have how many pixels into the character square we're starting at]
push af ; Save A
ex af, af'
ld a, d ; Put y Coord into A'
sra a ; Divide by 2
sra a ; Divide by another 2 (/4 total)
sra a ; Divide by another 2 (/8) [Gives us a 1/3 of screen number]
add a, 88 ; Add in start of screen attributes high byte
ld h, a ; And put the result in H
ld a, d ; grab our Y co-ord again
and 7 ; Mod 8 (why? *I thought to give a line in this 1/3 of screen, but we're in attrs here)
rrca ;
rrca
rrca ; Bring the bottom 3 bits to the top - Multiply by 32
; (since there are 32 bytes across the screen), here, in other words. [Faster than 5 SLA instructions]
add a, e ; add in our x coordinate byte to give us a low screen byte
ld l, a ; Put the result in L. So now HL -> screen byte at the top of the character
ld a, (23693) ; ATTR P Permanent current colours, etc (as set up by colour statements).
ld e, a ; Copy ATTR into e
ld (hl), e ; Drop ATTR value into screen
inc hl ; Go to next position along
pop af ; Pull how many pixels into this square we are
cp 3 ; It more than 2?
jr c, hop1 ; No? It all fits in this square - jump changing the next attribute
ld (hl), e ; 63446 Must be yes - we're setting the attributes in the next square too.
LOCAL hop1
hop1:
dec hl ; Back up to last position
ld a, d ; Y Coord into A'
and 248 ; Turn it into 0,8 or 16. (y=0-23)
add a, 64 ; Turn it into 64,72,80 [40,48,50 Hex] for high byte of screen pos
ld h, a ; Stick it in H
push hl ; Save it
exx ; Swap registers
pop hl ; Put it into H'L'
exx ; Swap Back
ld a, 8
LOCAL hop4
hop4:
push af ; Save Accumulator
ld a, (bc) ; Grab a byte of workspace
exx ; Swap registers
push hl ; Save h'l'
ld c, 0 ; put 0 into c'
ld de, 1023 ; Put 1023 into D'E'
ex af, af' ; Swap AF
and a ; Flags on A
jr z, hop3 ; If a is zero jump forward
ld b, a ; A -> B
ex af, af' ; Swap to A'F'
LOCAL hop2
hop2:; Slides a byte right to the right position in the block (and puts leftover bits in the left side of c)
and a ; Clear Carry Flag
rra ; Rotate Right A
rr c ; Rotate right C (Rotates a carry flag off A and into C)
scf ; Set Carry Flag
rr d ; Rotate Right D
rr e ; Rotate Right E (D flows into E, with help from the carry bit)
djnz hop2 ; Decrement B and loop back
ex af, af'
LOCAL hop3
hop3:
ex af, af'
ld b, a
ld a, (hl)
and d
or b
ld (hl), a ; Write out our byte
inc hl ; Go one byte right
ld a, (hl) ; Bring it in
and e
or c ; mix those leftover bits into the next block
ld (hl), a ; Write it out again
pop hl
inc h ; Next line
exx
inc bc ; Next workspace byte
pop af
dec a
jr nz, hop4 ; And go back!
exx ; Tidy up
pop hl ; Clear stack leftovers
exx ; And...
ret ; Go home.
LOCAL mult8
mult8: ; Multiplies L by 8 -> HL and adds it to DE. Used for 8 byte table vectors.
ld h, 0
add hl, hl
add hl, hl
add hl, hl
add hl, de
ret
LOCAL testcoords
testcoords:
ld de, (xycoords) ; get our current screen co-ordinates (d=y,e=x - little endian)
LOCAL nxtchar
nxtchar:
ld a, e
cp 42 ; Are we >42?
jr c, ycoord ; if not, hop forward
LOCAL nxtline
nxtline:
inc d ; if so, so bump us to the next line down
ld e, 0 ; and reset x to left edge
LOCAL ycoord
ycoord:
ld a, d
cp 24 ; are we >24 lines?
ret c ; if no, exit subroutine
ld d, 0 ; if yes, wrap around to top line again.
ret ; exit subroutine
end asm
printAt42Coords:
asm
LOCAL xycoords
xycoords:
defb 0 ; x coordinate
defb 0 ; y coordinate
LOCAL workspace
workspace:
defb 0
defb 0
defb 0
defb 0
defb 0
defb 0
defb 0
defb 0
; The data below identifies a column in the character to remove. It consists of 1's
; from the left edge. First zero bit is the column we're removing.
; If the leftmost bit is NOT 1, then the byte represents a redefined character position
; in the lookup table.
LOCAL whichcolumn
whichcolumn:
defb 254 ; SPACE
defb 254 ; !
defb 128 ; ""
defb 224 ; #
defb 128 ; $
defb 0 ; % (Redefined below)
defb 1 ; & (Redefined below)
defb 128 ; '
defb 128 ; (
defb 128 ; )
defb 128 ; *
defb 128 ; +
defb 128 ; ,
defb 128 ; -
defb 128 ; .
defb 128 ; /
defb 2 ; 0 (Redefined below)
defb 128 ; 1
defb 224 ; 2
defb 224 ; 3
defb 252 ; 4
defb 224 ; 5
defb 224 ; 6
defb 192 ; 7
defb 240 ; 8
defb 240 ; 9
defb 240 ; :
defb 240 ; ;
defb 192 ; <
defb 240 ; =
defb 192 ; >
defb 192 ; ?
defb 248 ; @
defb 240 ; A
defb 240 ; B
defb 240 ; C
defb 240 ; D
defb 240 ; E
defb 240 ; F
defb 240 ; G
defb 240 ; H
defb 128 ; I
defb 240 ; J
defb 192 ; K
defb 240 ; L
defb 240 ; M
defb 248 ; N
defb 240 ; O
defb 240 ; P
defb 248 ; Q
defb 240 ; R
defb 240 ; S
defb 3 ; T
defb 240 ; U
defb 240 ; V
defb 240 ; W
defb 240 ; X
defb 4 ; Y
defb 252 ; Z
defb 224 ; [
defb 252 ; \
defb 240 ; ]
defb 252 ; ^
defb 6 ; _
defb 240 ; UK Pound (Currency) Symbol
defb 255 ; a
defb 128 ; b
defb 255 ; c
defb 255 ; d
defb 255 ; e
defb 255 ; f
defb 255 ; g
defb 255 ; h
defb 255 ; i
defb 255 ; j
defb 255 ; k
defb 255 ; l
defb 255 ; m
defb 255 ; n
defb 255 ; o
defb 255 ; p
defb 255 ; q
defb 255 ; r
defb 255 ; s
defb 255 ; t
defb 255 ; u
defb 255 ; v
defb 255 ; w
defb 255 ; x
defb 255 ; y
defb 255 ; z
defb 128 ; {
defb 128 ; |
defb 255 ; }
defb 128 ; ~
defb 5 ; (c) end column data
LOCAL characters
characters:
defb 0 ; %
defb 0
defb 100
defb 104
defb 16
defb 44
defb 76
defb 0
defb 0 ; &
defb 32
defb 80
defb 32
defb 84
defb 72
defb 52
defb 0
defb 0 ; digit 0
defb 56
defb 76
defb 84
defb 84
defb 100
defb 56
defb 0
defb 0 ; Letter T
defb 124
defb 16
defb 16
defb 16
defb 16
defb 16
defb 0
defb 0 ; Letter Y
defb 68
defb 68
defb 40
defb 16
defb 16
defb 16
defb 0
defb 0 ; (c) symbol
defb 48
defb 72
defb 180
defb 164
defb 180
defb 72
defb 48
defb 0
defb 0
defb 0
defb 0
defb 0
defb 0
defb 0
defb 0xFC
LOCAL print42end
print42end:
ENDP
end asm
END SUB
#pragma pop(case_insensitive)
#endif