commit 37085b3

zzo38  ·  2026-02-28 06:48:08 +0000 UTC
parent 4c459d5
Implement use of compact fonts in assembler.
2 files changed,  +130, -6
+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+
+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 }