-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecode.asm
More file actions
94 lines (84 loc) · 2.75 KB
/
decode.asm
File metadata and controls
94 lines (84 loc) · 2.75 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
;; Given a destination address and the varptr of a BASIC
;; string, copy the source string to the destination,
;; processing !-escapes by replacing each '!' with the
;; subsequent character with the high-bit flipped.
;; Optionally, rotate the character-set.
;; Calling is a two step process. First, the destination
;; address is sent from BASIC in HL by calling DCINIT.
;; Second, MAIN (= DCINIT+9) is called with the varptr of
;; the source string in HL.
;; The call to DCINIT also specifies a number in register A
;; from 0 to 255 to be subtracted from every byte. This allows
;; the coding to be more efficient by rotating the character
;; set.
;; Upon return, the length of the source string is modified to
;; reflect the actual number of characters written to the
;; destination address. The source string data is NOT changed.
;; Example usage from BASIC:
;; 10 DC=(DCINIT address after relocation)
;; 15 A=(rotation offset or 0)
;; 20 Q=(destination buffer address)
;; 30 READ P$: IF P$="EOD" THEN END
;; 40 CALL DC, A, Q
;; 50 CALL DC+9, 0, VARPTR(P$)
;; 60 Q=Q+LEN(P$)
;; 70 GOTO 30
;;
;; When appending multiple strings to the same buffer, the
;; destination address does not need to be updated each time.
;; The following is equivalent to the above code:
;; 10 DC=(DCINIT address after relocation)
;; 15 A=(rotation offset or 0)
;; 20 CALL DC, A, (destination buffer address)
;; 30 READ P$: IF P$="EOD" THEN END
;; 40 CALL DC+9, 0, VARPTR(P$)
;; 50 GOTO 30
CPU 8085 ; Build with asmx -w -e -l -b0 decode.asm
ORG 0 ; The BASIC loader relocates this routine.
DCINIT:
STA ROT ; Save A as Rotation Offset for charset
SHLD DEST ; Save HL in DEST as destination address.
RET
DEST: DW 0
MAIN:
;; HL starts as VARPTR(P$) where P$ is bang-encoded.
PUSH H
MOV B, M ; B is length of input string
MVI C, 0 ; C will be resulting length
INX H
MOV E, M ; Load actual address of string into DE
INX H
MOV D, M
LHLD DEST ; Restore HL from saved DEST
XCHG ; Now HL is P$'s actual address
; and DE is address of destination
MOV A, B
ANA A
JZ END ; Zero-length string?
LOOP:
MOV A, M ; Get next byte from source (*HL)
CPI '!'
JNZ WRITE ; If not '!' just copy the character.
DCR B
JZ END ; Ignore escape char with no following char.
INX H ; Char is '!' so get next char in A
MOV A, M
XRI 128 ; Decode character by flipping bit 7
WRITE:
XCHG
DB D6h ; D6 is SUI instruction.
ROT: DB 0 ; Subtract this value from char.
MOV M, A ; Copy the byte from *HL to *DE.
XCHG
INX H
INX D
INR C
DCR B
JNZ LOOP
END:
XCHG ; Save DE in DEST so next call can skip DCINIT
SHLD DEST
XCHG ; Not needed, just being overly fastidious
POP H
MOV M, C ; Write new length to BASIC string
RET