commit 37085b3
zzo38
·
2026-02-28 06:48:08 +0000 UTC
parent 4c459d5
Implement use of compact fonts in assembler.
M
asm.doc
+28,
-0
1@@ -335,3 +335,31 @@ The following nonstandard tokens are used for expanded memory:
2 referenced by sub-assemblies in the same or an earlier block than the \*
3 is in, but can be referenced by sub-assemblies in any later block.
4
5+
6+=== Compact fonts ===
7+
8+There is also a nonstandard feature to make 8x8 fonts compact. This uses
9+the following nonstandard tokens:
10+
11+ [' and ]' surround a block that contains character codes to be remapped.
12+ Within this block, # and " and \~ and direct numeric data is affected,
13+ and anything else is not affected.
14+
15+ \m followed by a number and then ~ and a file name will treat that file
16+ as a raw 8x8 1bpp font, and will be copied into the output like \~ does
17+ but will delete unused characters from the font, and renumber the rest
18+ of the characters and change the data in the [' and ]' to the renumbered
19+ character codes; the number before ~ is the first character code number.
20+ After this, the address of character code zero (which is not necessarily
21+ a valid character code) is pushed to the special stack so that \@ can be
22+ used. The \m command cannot occur more than once. Any character codes
23+ that are beyond the end of the (full) font will be renumbered to numbers
24+ after the end of the font with the deleted characters, so that you can
25+ still add more characters in your own program beyond those in the font
26+ file that is specified.
27+
28+ \mk followed by two or four hex digits will cause those characters to be
29+ kept even if they are not used. If there are four hex digits, then it is
30+ a range (inclusive on both ends), and it will guarantee that they will be
31+ a contiguous range of character codes.
32+
M
uxnasm.c
+102,
-6
1@@ -82,6 +82,10 @@ static char spec_rune[128];
2 static Uint16 exstart;
3 static FILE*subas;
4
5+static Uint8 fontkeep[LENGTH/8];
6+static Uint8 fontmap[256];
7+static Uint8 fontdone,fontbloc;
8+
9 /* clang-format off */
10
11 static char ops[][4] = {
12@@ -266,6 +270,15 @@ writebyte(Uint8 b)
13 return 1;
14 }
15
16+static inline int
17+writebyte1(Uint8 b)
18+{
19+ if(p.ptr > 0xffff)
20+ return error("Writing after the end of RAM", "");
21+ if(fontbloc) fontkeep[p.ptr>>3]|=1<<(p.ptr&7);
22+ return writebyte(b);
23+}
24+
25 static int
26 writeopcode(char *w)
27 {
28@@ -282,6 +295,14 @@ writeshort(Uint16 s, int lit)
29 return writebyte(s >> 8) && writebyte(s & 0xff);
30 }
31
32+static inline int
33+writeshort1(Uint16 s, int lit)
34+{
35+ if(lit)
36+ if(!writebyte(findopcode("LIT2"))) return 0;
37+ return writebyte1(s >> 8) && writebyte1(s & 0xff);
38+}
39+
40 static int
41 writelitbyte(Uint8 b)
42 {
43@@ -290,6 +311,14 @@ writelitbyte(Uint8 b)
44 return 1;
45 }
46
47+static int
48+writelitbyte1(Uint8 b)
49+{
50+ if(!writebyte(findopcode("LIT"))) return 0;
51+ if(!writebyte1(b)) return 0;
52+ return 1;
53+}
54+
55 static int
56 doinclude(const char *filename)
57 {
58@@ -315,11 +344,38 @@ static int doinclude_binary(const char*filename) {
59 FILE*f;
60 int c;
61 if(!(f = fopen(filename, "r"))) return error("Include missing", filename);
62- while((c=fgetc(f))!=EOF) writebyte(c);
63+ while((c=fgetc(f))!=EOF) writebyte1(c);
64 fclose(f);
65 return 1;
66 }
67
68+static int doinclude_font(const char*filename,int first) {
69+ FILE*f;
70+ int i,j,m;
71+ if(fontdone) return error("Cannot include multiple fonts",filename);
72+ if(p.ptr < p.length) return error("Memory overwrite", "");
73+ if(p.ptr>63486) return error("Not enough space for font",filename);
74+ if(!(f = fopen(filename, "r"))) return error("Include missing", filename);
75+ m=fread(p.data+p.ptr,8,256,f);
76+ fclose(f);
77+ for(i=0;i<256;i++) fontmap[i]=i;
78+ for(i=0;i<first;i++) fontkeep[i>>3]|=1<<(i&7);
79+ for(i=TRIM;i<p.length && i<LENGTH;i++) if(fontkeep[i>>3]&(1<<(i&7))) {
80+ j=p.data[i];
81+ fontkeep[j>>3]|=1<<(j&7);
82+ }
83+ for(i=first;i<first+m && i<256;i++) {
84+ if(fontkeep[i>>3]&(1<<(i&7))) {
85+ p.ptr+=8; p.length=p.ptr;
86+ } else {
87+ for(j=i;j<256;j++) fontmap[j]--;
88+ memmove(p.data+p.ptr,p.data+p.ptr+8,(first+m-i)<<3);
89+ }
90+ }
91+ fontdone=1;
92+ return 1;
93+}
94+
95 static int special_calc(const char*w) {
96 const char*loop=w;
97 Uint16 a,b;
98@@ -476,9 +532,9 @@ parse(char *w, FILE *f)
99 if(!sihx(w + 1) || (slen(w) != 3 && slen(w) != 5))
100 return error("Invalid hex literal", w);
101 if(slen(w) == 3) {
102- if(!writelitbyte(shex(w + 1))) return 0;
103+ if(!writelitbyte1(shex(w + 1))) return 0;
104 } else if(slen(w) == 5) {
105- if(!writeshort(shex(w + 1), 1)) return 0;
106+ if(!writeshort1(shex(w + 1), 1)) return 0;
107 }
108 break;
109 case '.': /* literal byte zero-page */
110@@ -508,7 +564,7 @@ parse(char *w, FILE *f)
111 case '"': /* raw string */
112 i = 0;
113 while((c = w[++i]))
114- if(!writebyte(c)) return 0;
115+ if(!writebyte1(c)) return 0;
116 break;
117 case '?': /* JCI */
118 makereference(p.scope, w, p.ptr + 1);
119@@ -556,6 +612,30 @@ parse(char *w, FILE *f)
120 if(!exp_file(w+2)) return 0;
121 break;
122 case '+': w[1]='x'; makereference(0,w+1,1); break;
123+ case 'm':
124+ if(fontdone) return error("Cannot use \\m multiple times",w);
125+ if(w[2]=='k') {
126+ if(!sihx(w+3)) return error("Invalid special",w);
127+ if(slen(w+3)==2) {
128+ i=shex(w+3)&255;
129+ fontkeep[i>>3]|=1<<(i&7);
130+ } else if(slen(w+3)==4) {
131+ int j;
132+ i=shex(w+3)&0xFFFF; j=i&255; i>>=8;
133+ for(;i<=j;i++) fontkeep[i>>3]|=1<<(i&7);
134+ } else {
135+ return error("Invalid special",w);
136+ }
137+ } else {
138+ for(i=2;w[i] && w[i]!='~';i++);
139+ if(w[i]!='~') return error("Invalid special",w);
140+ w[i]=0;
141+ if(ssptr==256) return error("Stack overflow",w);
142+ if(!sihx(w+2)) return error("Invalid hex literal",w);
143+ sstack[ssptr++]=p.ptr-(shex(w+2)<<3);
144+ if(!doinclude_font(w+i+1,shex(w+2))) return 0;
145+ }
146+ break;
147 default: return error("Invalid special",w);
148 }
149 break;
150@@ -605,6 +685,10 @@ parse(char *w, FILE *f)
151 p.ptr=p.length=exstart;
152 }
153 break;
154+ } else if(w[1]=='\'' && !w[2]) {
155+ if((w[0]=='[')==fontbloc) return error("Misuse of [' or ]'",w);
156+ fontbloc=(w[0]=='[');
157+ break;
158 }
159 /* fall through */
160 default: defa:
161@@ -614,11 +698,11 @@ parse(char *w, FILE *f)
162 }
163 /* raw byte */
164 else if(sihx(w) && slen(w) == 2) {
165- if(!writebyte(shex(w))) return 0;
166+ if(!writebyte1(shex(w))) return 0;
167 }
168 /* raw short */
169 else if(sihx(w) && slen(w) == 4) {
170- if(!writeshort(shex(w), 0)) return 0;
171+ if(!writeshort1(shex(w), 0)) return 0;
172 }
173 /* macro */
174 else if((m = findmacro(w))) {
175@@ -833,6 +917,16 @@ static int align_expanded(void) {
176 return 1;
177 }
178
179+static int resolve_fontmap(void) {
180+ int i,j;
181+ for(i=TRIM;i<p.length;i++) if(fontkeep[i>>3]&(1<<(i&7))) {
182+ j=p.data[i];
183+ if(!(fontkeep[j>>3]&(1<<(j&7)))) return error("Use of font character that has been deleted","");
184+ p.data[i]=fontmap[j];
185+ }
186+ return 1;
187+}
188+
189 static int
190 assemble(FILE *f)
191 {
192@@ -847,7 +941,9 @@ assemble(FILE *f)
193 line_comment=0;
194 }
195 }
196+ if(fontbloc) return error("Misuse of [' and ]'", "");
197 p.total=p.length;
198+ if(fontdone && !resolve_fontmap()) return 0;
199 if(p.xlen && !align_expanded()) return 0;
200 return resolve();
201 }