1 #include <unistd.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdio.h> 5 #include <math.h> 6 7 struct sf_machine { 8 size_t cs_size; 9 unsigned char *buf; 10 unsigned char *dp; 11 size_t buflen; 12 unsigned char flags_hlt; 13 unsigned char *ip_stack[1024]; /* stack for handling instruction pointer */ 14 unsigned char **ip; /* current position in ip_stack */ 15 }; 16 17 typedef enum { 18 INT_HLT = 0, 19 INT_PRT = 1, 20 INT_PRTC = 2, 21 INT_GETC = 3 22 } interrupt_t; 23 24 void sf_dump(struct sf_machine *sys, const char *pre_msg, const char *post_msg) { 25 size_t i, highest_offset; 26 27 for (i = (sys->buflen - 1); i; i--) { 28 if (sys->buf[i]) { 29 highest_offset = i + 1; 30 break; 31 } 32 } 33 34 printf("********************************\n"); 35 if (pre_msg) { 36 printf("%s\n", pre_msg); 37 } 38 printf("IPI = %i (%c)\n", (*sys->ip)[0], (*sys->ip)[0]); 39 printf("IPA = %i\n", (*sys->ip)[1]); 40 printf("IP = %llu\n", (unsigned long long) (*sys->ip - sys->buf) - 1); 41 printf("DP = %llu\n", (unsigned long long) (sys->dp - sys->buf) - 1); 42 printf("Contents of the buffer:\n"); 43 for (i = (sys->cs_size + 1 + 1024); i < highest_offset; i++) { 44 if ((i % 18) == 0) { 45 printf(" "); 46 } 47 printf("%c%3i,", ' ', sys->buf[i]); 48 if (((i + 1) % 18) == 0) { 49 printf("\n"); 50 } 51 } 52 if (((i + 1) % 18) != 0) { 53 printf("\n"); 54 } 55 56 printf("\n"); 57 if (post_msg) { 58 printf("%s\n", post_msg); 59 } 60 } 61 62 int sys_loadimage(const char *filename, struct sf_machine *sys) { 63 unsigned char tmpbuf; 64 size_t fread_ret; 65 FILE *fp; 66 67 fp = fopen(filename, "r"); 68 if (!fp) { 69 return(-1); 70 } 71 72 fread_ret = fread(&tmpbuf, 1, 1, fp); 73 if (fread_ret != 1) { 74 fclose(fp); 75 return(-1); 76 } 77 78 sys->cs_size = pow(2, tmpbuf) * 1024; 79 /* 80 * 640K ought to be enough for anybody. 81 */ 82 sys->buflen = 1 + sys->cs_size + 1024 + (640 * 1024); 83 sys->buf = malloc(sys->buflen); 84 if (!sys->buf) { 85 fclose(fp); 86 return(-1); 87 } 88 89 memset(sys->buf, 0, sys->buflen); 90 91 sys->buf[0] = tmpbuf; 92 sys->ip_stack[0] = sys->buf + 1; 93 sys->ip = sys->ip_stack; 94 sys->dp = sys->buf + 1 + sys->cs_size + 1024; 95 96 sys->buf++; 97 while (1) { 98 fread_ret = fread(sys->buf, 1, 8192, fp); 99 if (fread_ret <= 0) { 100 break; 101 } 102 sys->buf += fread_ret; 103 } 104 105 sys->buf = *sys->ip - 1; 106 sys->flags_hlt = 0; 107 108 fclose(fp); 109 110 if (fread_ret < 0) { 111 return(-1); 112 } 113 114 return(0); 115 } 116 117 void call_int(struct sf_machine *sys, unsigned char interrupt) { 118 switch ((interrupt_t) interrupt) { 119 case INT_HLT: 120 sys->flags_hlt = 1; 121 break; 122 case INT_PRT: 123 printf("%s", sys->dp); 124 break; 125 case INT_PRTC: 126 printf("%c", sys->dp[0]); 127 break; 128 case INT_GETC: 129 sys->dp[0] = getchar(); 130 break; 131 } 132 133 return; 134 } 135 136 void sys_run(struct sf_machine *sys) { 137 unsigned char *buf; 138 unsigned char ipi, ipa; 139 unsigned long iv, iv_loc; 140 long test_depth; 141 142 buf = sys->buf; 143 144 while (1) { 145 ipi = (*sys->ip)[0]; 146 ipa = (*sys->ip)[1]; 147 148 switch (ipi) { 149 case '+': 150 (*sys->dp) += ipa; 151 break; 152 case '-': 153 (*sys->dp) -= ipa; 154 break; 155 case '>': 156 sys->dp += ipa; 157 break; 158 case '<': 159 sys->dp -= ipa; 160 break; 161 case '[': 162 if (!*sys->dp) { 163 /* 164 * If the value at (dp) is 0 then: 165 * Move IP to the matching close brace 166 * instruction 167 */ 168 test_depth = 1; 169 while (test_depth) { 170 (*sys->ip)++; 171 if (**sys->ip == '[') { 172 test_depth++; 173 } else if (**sys->ip == ']') { 174 test_depth--; 175 } 176 } 177 } 178 break; 179 case ']': 180 if (*sys->dp) { 181 /* 182 * If the value at (dp) is non-zero then: 183 * Move IP to the matching open brace 184 * instruction. 185 */ 186 test_depth = -1; 187 while (test_depth) { 188 (*sys->ip)--; 189 if(**sys->ip == '[') { 190 test_depth++; 191 } else if (**sys->ip == ']') { 192 test_depth--; 193 } 194 } 195 } 196 break; 197 case '*': 198 iv_loc = sys->cs_size + 1 + (ipa * 4); 199 iv = sys->buf[iv_loc] << 24; 200 iv |= sys->buf[iv_loc + 1] << 16; 201 iv |= sys->buf[iv_loc + 2] << 8; 202 iv |= sys->buf[iv_loc + 3]; 203 204 if (iv) { 205 sys->ip++; 206 *sys->ip = sys->buf + iv - 2; 207 } else { 208 call_int(sys, ipa); 209 } 210 break; 211 case '!': 212 sys->ip--; 213 break; 214 default: 215 sys->flags_hlt = 1; 216 break; 217 } 218 219 if (sys->flags_hlt) { 220 break; 221 } 222 223 (*sys->ip) += 2; 224 } 225 226 return; 227 } 228 229 int main(int argc, char **argv) { 230 struct sf_machine sf_sys; 231 char *image_name; 232 int retval; 233 234 if (argc != 2) { 235 fprintf(stderr, "Usage: sf <image>\n"); 236 return(EXIT_FAILURE); 237 } 238 239 image_name = argv[1]; 240 241 retval = sys_loadimage(image_name, &sf_sys); 242 if (retval < 0) { 243 fprintf(stderr, "Error loading image.\n"); 244 return(EXIT_FAILURE); 245 } 246 247 sys_run(&sf_sys); 248 249 fprintf(stderr, "***** HALTED *****\n"); 250 251 sf_dump(&sf_sys, NULL, NULL); 252 253 return(EXIT_SUCCESS); 254 } |