2 // coded by Ketmar // Vamprile Avalon
15 #include <sys/types.h>
23 #include "urasmlib/urasmlib.h"
32 #define MAYBE_UNUSED __attribute__((unused))
34 ///////////////////////////////////////////////////////////////////////////////
37 static char *sysIncludeDir
= NULL
;
39 #define MAX_LINE_SIZE 16384
40 static char curLine
[MAX_LINE_SIZE
]; /* current processing line; can be freely modified */
43 ///////////////////////////////////////////////////////////////////////////////
46 static void initInclideDir (void) {
47 const char *id
= getenv("URASM_INCLUDE_DIR");
49 sysIncludeDir
= strdup(id
);
51 char buf
[128], myDir
[4096];
54 sprintf(buf
, "/proc/%u/exe", (unsigned int)pid
);
55 memset(myDir
, 0, sizeof(myDir
));
56 if (readlink(buf
, myDir
, sizeof(myDir
)-1) < 0) strcpy(myDir
, ".");
58 char *p
= (char *)strrchr(myDir
, '/');
59 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
61 strcat(myDir
, "/libs");
64 memset(myDir
, 0, sizeof(myDir
));
65 GetModuleFileName(GetModuleHandle(NULL
), myDir
, sizeof(myDir
)-1);
66 p
= strrchr(myDir
, '\\');
67 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
68 strcat(myDir
, "\\libs");
70 sysIncludeDir
= strdup(myDir
);
72 while (sysIncludeDir
[0] && sysIncludeDir
[strlen(sysIncludeDir
)-1] == '/') sysIncludeDir
[strlen(sysIncludeDir
)-1] = '\0';
73 if (!sysIncludeDir
[0]) strcpy(sysIncludeDir
, ".");
77 ///////////////////////////////////////////////////////////////////////////////
80 /*TODO: expression parser should understant escapes in strings!*/
81 /* trim trailing spaces and comments */
82 static void normalizeStr (char *s
) {
86 for (p
= s
; *p
; ++p
) {
91 case 'x': case 'X': // hex code
93 for (f
= 0; f
< 2; ++f
) if (!isxdigit(*p
)) break;
94 --p
; // last digit will be skiped by 'for'
96 case '0': // octal code
97 for (f
= 0; f
< 4; ++f
) if (!isdigit(*p
) || *p
> '7') break;
98 --p
; // last digit will be skiped by 'for'
100 case '1' ... '9': // decimal code
101 for (f
= 0; f
< 3; ++f
) if (!isdigit(*p
)) break;
102 --p
; // last digit will be skiped by 'for'
104 default: ; // other escapes, do nothing
107 if (*p
== inQ
) inQ
= 0;
111 // outside the string
113 case '"': case '\'': // string catched
116 case ';': // end of line, comment follows
117 *p
-- = '\0'; // strip it and quit
119 default: ; // do nothing
123 for (p
= s
+strlen(s
)-1; p
>= s
&& isspace(*p
); --p
) ;
128 /* returns NULL or pointer to args */
129 /* skips spaces after command if any */
130 static char *strIsCommand (const char *command
, char *str
) {
133 for (cnt
= 1; cnt
> 0; --cnt
) {
134 while (*str
&& isspace(*str
)) ++str
; // skip spaces
135 for (; *command
&& *str
; ++command
, ++str
) {
136 if (toupper(*command
) != toupper(*str
)) return NULL
; // alas
138 if (*command
) return NULL
; // alas
139 if (*str
&& isalnum(*str
)) return NULL
; // alas
140 while (*str
&& isspace(*str
)) ++str
; // skip spaces
141 if (*str
&& *str
== ':') break; // try again if we have a colon
148 /* don't free() result */
149 /* skips trailing spaces */
150 static char *parseStr (char **str
, char endQ
, int *lenp
) {
151 static char buf
[MAX_LINE_SIZE
];
152 int len
= 0, n
, f
, base
;
155 int xDigit (char ch
, int base
) {
156 if (ch
< '0') return -1;
158 if (ch
>= '0'+base
) return -1;
162 if (ch
<= '9') return ch
-'0';
163 if (ch
< 'A' || ch
> 'A'+base
-10) return -1;
165 return ch
<base
? ch
: -1;
168 memset(buf
, 0, sizeof(buf
));
174 case 'a': buf
[len
++] = '\a'; break;
175 case 'b': buf
[len
++] = '\b'; break;
176 case 'f': buf
[len
++] = '\f'; break;
177 case 'n': buf
[len
++] = '\n'; break;
178 case 'r': buf
[len
++] = '\r'; break;
179 case 't': buf
[len
++] = '\t'; break;
180 case 'v': buf
[len
++] = '\v'; break;
181 case 'z': buf
[len
++] = '\0'; break;
182 case 'x': case 'X': // hex
185 donum
: for (n
= 0; f
> 0; --f
) {
186 char ch
= xDigit(*a
++, base
);
187 if (ch
< 0) { --a
; break; }
192 --a
; // return to the last digit, 'for' will skip it
197 case '1' ... '9': // decimal
200 default: buf
[len
++] = a
[0]; break; // others
203 if (*a
== endQ
) { ++a
; break; }
207 while (*a
&& isspace(*a
)) ++a
; // skip trailing spaces
210 if (lenp
) *lenp
= len
;
215 ///////////////////////////////////////////////////////////////////////////////
216 // source file stack, reader, etc
218 typedef struct SourceLine SourceLine
;
226 static SourceLine
*asmText
= NULL
;
227 static SourceLine
*asmTextLast
= NULL
;
228 static SourceLine
*curSrcLine
= NULL
;
231 static void asmTextClear (void) {
233 SourceLine
*l
= asmText
;
234 asmText
= asmText
->next
;
239 asmTextLast
= curSrcLine
= NULL
;
243 static void normIncName (char *dest
, const char *fn
, int system
) {
246 if (system
) sprintf(dest
, "%s/%s", sysIncludeDir
, fn
); else sprintf(dest
, "%s", fn
);
247 if (stat(dest
, &st
)) return;
248 if (S_ISDIR(st
.st_mode
)) strcat(dest
, "/zzmain.zas");
252 static int asmTextLoad (const char *fname
) {
257 static int includeCount
= 0;
259 if (!(fl
= fopen(fname
, "r"))) {
260 fprintf(stderr
, "ERROR: can't open file: %s\n", fname
);
263 printf("loading: %s\n", fname
);
265 while (fgets(curLine
, sizeof(curLine
)-1, fl
)) {
267 curLine
[sizeof(curLine
)-1] = '\0';
268 normalizeStr(curLine
);
269 if (!curLine
[0]) continue; // don't store empty lines
270 // find specials, if any
271 if (isspace(curLine
[0])) {
272 if ((args
= strIsCommand("INCLUDE", curLine
)) != NULL
) {
279 fprintf(stderr
, "ERROR: file %s, line %d: invalid INCLUDE!\n", fname
, lineNo
);
282 if (args
[0] == '"' || args
[0] == '\'') qCh
= *args
++;
283 else if (args
[0] == '<') { qCh
= '>'; ++args
; system
= 1; }
284 char *fn
= parseStr(&args
, qCh
, NULL
); // i don't care about string length here
287 fprintf(stderr
, "ERROR: file %s, line %d: can't INCLUDE nothing!\n", fname
, lineNo
);
292 fprintf(stderr
, "ERROR: file %s, line %d: extra args after INCLUDE filename!\n", fname
, lineNo
);
295 if (includeCount
> 256) {
297 fprintf(stderr
, "ERROR: file %s, line %d: too many nested INCLUDEs!\n", fname
, lineNo
);
300 normIncName(curLine
, fn
, system
);
301 //if (system) sprintf(curLine, "%s/%s", sysIncludeDir, fn); else sprintf(curLine, "%s", fn);
302 fn
= strdup(curLine
); if (!fn
) abort();
304 system
= asmTextLoad(fn
);
307 if (system
) { fclose(fl
); return system
; }
312 s
= calloc(1, sizeof(SourceLine
));
315 s
->line
= strdup(curLine
); if (!s
->line
) abort();
316 s
->fname
= strdup(fname
); if (!s
->fname
) abort();
317 if (asmTextLast
) asmTextLast
->next
= s
; else asmText
= s
;
325 static inline void loadCurSrcLine (void) { if (curSrcLine
) strcpy(curLine
, curSrcLine
?curSrcLine
->line
:""); }
326 static inline SourceLine
*setCurSrcLine (SourceLine
*l
) { curSrcLine
= l
; loadCurSrcLine(); return l
; }
327 static inline SourceLine
*nextSrcLine (void) { return curSrcLine
? setCurSrcLine(curSrcLine
->next
) : NULL
; }
330 ///////////////////////////////////////////////////////////////////////////////
333 static void processCurrentLine (void); // only one, will skip to next one
336 ///////////////////////////////////////////////////////////////////////////////
337 // error raisers, etc
339 static jmp_buf errJP
;
342 static void errorWriteFile (void) {
344 fprintf(stderr
, "at file %s, line %d\n%s\n*", curSrcLine
->fname
, curSrcLine
->lineNo
, curSrcLine
->line
);
346 fprintf(stderr
, "somewhere in time: ");
350 static void errorMsgV (const char *fmt
, va_list ap
) {
352 vfprintf(stderr
, fmt
, ap
);
359 static void __attribute__((format(printf
, 1, 2))) warningMsg (const char *fmt
, ...) {
361 fprintf(stderr
, "WARNING ");
367 static void __attribute__((format(printf
, 1, 2))) errorMsg (const char *fmt
, ...) {
369 fprintf(stderr
, "FATAL ");
375 static void __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2))) fatal (const char *fmt
, ...) {
383 static void __attribute__((noreturn
)) fatalUrLib (int errcode
) {
384 errorMsg("%s", urErrorMessage(errcode
));
389 //////////////////////////////////////////////////////////////////////////////
390 // operator management
392 typedef void (*UrAsmOpFn
) (void);
394 typedef struct UrAsmOp UrAsmOp
;
401 static UrAsmOp
*oplist
= NULL
;
404 static UrAsmOp
*urAddOp (const char *name
, UrAsmOpFn fn
) {
405 UrAsmOp
*res
= calloc(1, sizeof(UrAsmOp
));
407 res
->name
= strdup(name
);
415 static UrAsmOp
*urFindOp (const char *name
) {
417 for (res
= oplist
; res
; res
= res
->next
) if (!strcasecmp(name
, res
->name
)) break;
422 static void urClearOps (void) {
425 c
= oplist
; oplist
= oplist
->next
;
432 ///////////////////////////////////////////////////////////////////////////////
435 typedef struct UrLabelInfo UrLabelInfo
;
439 int type
; /* -1: uknown (forward reference); 0: =; 1: equ; 2: code */
440 int known
; /* !0: label value already known */
441 int refLine
; /* first referenced line */
446 static UrLabelInfo
*labels
= NULL
;
448 static void urClearLabels (void) {
450 while ((c
= labels
)) {
451 labels
= labels
->next
;
452 if (c
->name
) free(c
->name
);
453 if (c
->refFile
) free(c
->refFile
);
459 static UrLabelInfo
*urFindLabel (const char *name
) {
461 for (c
= labels
; c
; c
= c
->next
) if (!strcmp(name
, c
->name
)) break;
466 static UrLabelInfo
*urAddLabel (const char *name
) {
467 UrLabelInfo
*c
= urFindLabel(name
);
470 for (p
= NULL
, c
= labels
; c
; p
= c
, c
= c
->next
) ;
471 c
= calloc(1, sizeof(UrLabelInfo
));
473 c
->name
= strdup(name
);
475 if (p
) p
->next
= c
; else labels
= c
;
482 ///////////////////////////////////////////////////////////////////////////////
483 // module list management
485 typedef struct ModuleInfo ModuleInfo
;
488 char *fname
; // opened in this file
489 int seen
; // !0: module already seen, skip other definitions from the same file
492 static ModuleInfo
*modules
= NULL
;
493 static ModuleInfo
*curModule
= NULL
;
496 static void modulesClear (void) {
499 ModuleInfo
*c
= modules
;
500 modules
= modules
->next
;
508 static void modulesResetSeen (void) {
510 for (c
= modules
; c
; c
= c
->next
) c
->seen
= 0;
514 static ModuleInfo
*moduleFind (const char *name
) {
516 if (!name
|| !name
[0]) return NULL
;
517 for (c
= modules
; c
; c
= c
->next
) if (!strcmp(c
->name
, name
)) break;
522 static ModuleInfo
*moduleAdd (const char *name
, const char *fname
) {
524 if (!name
|| !fname
|| !name
[0] || !fname
[0]) abort();
525 c
= calloc(1, sizeof(ModuleInfo
));
527 c
->name
= strdup(name
); if (!c
->name
) abort();
528 c
->fname
= strdup(fname
); if (!c
->fname
) abort();
535 ///////////////////////////////////////////////////////////////////////////////
536 // destination memory management
538 static uint8_t memory
[65536];
539 static char memused
[65536];
540 static char memresv
[65536];
541 static uint16_t pc
= 0; /* current position to write */
542 static uint16_t disp
= 0; /* current 'virtual PC' */
543 static uint16_t ent
= 0; /* eng */
544 static uint16_t clrAddr
= 24999; /* address for CLEAR for cargador */
545 static int pass
= 0; /* 0: collect labels; 1: compiling; 2: compiling and fixing labels */
546 static int inTapeBlock
= 0;
547 static uint8_t tapeXorB
= 0;
550 static uint8_t getByte (uint16_t addr
) {
555 static __attribute__((unused
)) uint16_t getWord (uint16_t addr
) {
556 return ((uint16_t)memory
[addr
])|(((uint16_t)memory
[addr
+1])<<8);
560 static void putByte (uint16_t addr
, uint8_t b
) {
561 if (inTapeBlock
) tapeXorB
^= b
;
567 static MAYBE_UNUSED
void putWord (uint16_t addr
, uint16_t w
) {
568 putByte(addr
, w
&0xFFU
);
569 putByte(addr
+1, (w
>>8)&0xFFU
);
573 static void emitByte (uint8_t b
) {
579 static void emitWord (uint16_t w
) {
581 emitByte((w
>>8)&0xFFU
);
585 static void emitRWord (uint16_t w
) {
586 emitByte((w
>>8)&0xFFU
);
591 static void prepareMemory (void) {
592 memset(memory
, 0, sizeof(memory
));
593 memset(memused
, 0, sizeof(memused
));
594 memset(memresv
, 0, sizeof(memresv
));
598 ///////////////////////////////////////////////////////////////////////////////
599 // label getter and utilities
601 static char *lastSeenGlobalLabel
= NULL
; /* global */
604 static char *fixLocalLabel (const char *name
) {
605 static char newname
[MAX_LINE_SIZE
*2+1024];
607 memset(newname
, 0, sizeof(newname
));
608 if (!name
|| !name
[0]) newname
[0] = '\0';
609 else if (!lastSeenGlobalLabel
|| name
[0] != '.') strcpy(newname
, name
);
611 // this is local label, let's rename it
612 sprintf(newname
, "{%s%s}", lastSeenGlobalLabel
, name
);
618 static char *fixGlobalLabel (const char *name
) {
619 static char newname
[MAX_LINE_SIZE
*2+1024];
621 memset(newname
, 0, sizeof(newname
));
622 if (!name
|| !name
[0]) newname
[0] = '\0';
623 else if (!curModule
|| name
[0] == '.' || name
[0] == '{' || name
[0] == '@' || strchr(name
, '.')) {
624 if (name
[0] == '@' && name
[1]) ++name
;
625 strcpy(newname
, name
);
627 // this is global unqualified label and we have a module; let's rename it
628 sprintf(newname
, "%s.%s", curModule
->name
, name
);
630 //printf("%s --> %s\n", name, newname);
635 static int lblOptMakeU2
= 0;
636 static int32_t findLabelCB (const char *name
, uint16_t addr
, int *defined
, int *found
) {
640 nn
= fixGlobalLabel((ln
= fixLocalLabel(name
)));
641 lbl
= urFindLabel(nn
);
643 // try non-module label
644 lbl
= urFindLabel(ln
);
648 errorMsg("using undefined label %s", ln
);
653 lbl
= urAddLabel(nn
);
654 lbl
->type
= lblOptMakeU2
? -42 : -1;
656 lbl
->refLine
= curSrcLine
->lineNo
;
657 lbl
->refFile
= strdup(curSrcLine
->fname
);
658 //printf("new label: [%s]\n", lbl->name);
660 //printf("label reference: [%s]\n", lbl->name);
664 *defined
= lbl
->known
!=0;
673 static int isLabelDefinedOrKnown (const char *name
, uint16_t addr
, int qtype
) {
677 nn
= fixGlobalLabel((ln
= fixLocalLabel(name
)));
678 lbl
= urFindLabel(nn
);
680 // try non-module label
681 lbl
= urFindLabel(ln
);
684 case UR_QTYPE_DEFINED
: return lbl
? lbl
->known
!=0 : 0;
685 case UR_QTYPE_KNOWN
: return lbl
!=NULL
;
692 static int checkLabels (void) {
696 for (c
= labels
; c
; c
= c
->next
) {
698 fprintf(stderr
, "ERROR at file %s, line %d: referencing undefined label: %s\n", c
->refFile
, c
->refLine
, c
->name
);
701 if (c
->type
== 0) c
->known
= -1;
703 //if (wasError) longjmp(errJP, 667);
708 ///////////////////////////////////////////////////////////////////////////////
711 static int32_t getExprArg (int *defined
) {
716 while (*a
&& isspace(*a
)) ++a
;
717 if (!a
[0]) fatal("expression expected");
718 const char *ee
= urExpression(&res
, a
, disp
, defined
, &error
);
719 if (error
) fatalUrLib(error
);
721 if (ee
[0] != ',') fatal("bad expression");
722 memmove(curLine
, ee
, strlen(ee
)+1);
730 static int32_t getOneExprArg (int *defined
) {
731 int32_t res
= getExprArg(defined
);
732 if (curLine
[0]) fatal("too many expressions");
737 static int isStrArg (void) { return curLine
[0]=='"' || curLine
[0] == '\''; }
740 static char *getStrArg (int *lenp
) {
744 while (*a
&& isspace(*a
)) ++a
;
746 if (qCh
!= '"' && qCh
!= '\'') fatal("string expected");
747 res
= parseStr(&a
, qCh
, lenp
);
749 if (a
[0] != ',') fatal("bad string expression");
750 memmove(curLine
, a
, strlen(a
)+1);
758 static MAYBE_UNUSED
char *getOneStrArg (int *lenp
) {
759 char *res
= getStrArg(lenp
);
760 if (curLine
[0]) fatal("too many expressions");
765 static char *getLabelArg (void) {
766 static char res
[MAX_LINE_SIZE
+128], *p
;
769 memset(res
, 0, sizeof(res
));
770 while (*a
&& isspace(*a
)) ++a
;
771 if (!a
[0]) fatal("label expected");
772 for (p
= res
; *a
&& *a
!= ','; ++a
, ++p
) *p
= *a
;
773 for (; p
> res
&& isspace(p
[-1]); --p
) ;
775 if (p
-res
> 120) fatal("label name too long: %s", res
);
776 while (*a
&& isspace(*a
)) ++a
;
778 if (a
[0] != ',') fatal("bad string expression");
779 memmove(curLine
, a
, strlen(a
)+1);
787 static char *getOneLabelArg (void) {
788 char *res
= getLabelArg();
789 if (curLine
[0]) fatal("too many expressions");
794 /* res!=0: end of expression */
795 static int skipComma (void) {
797 for (a
= curLine
; *a
&& isspace(*a
); ++a
) ;
798 if (!a
[0]) { curLine
[0] = '\0'; return 0; }
799 if (a
[0] != ',') fatal("invalid expression: ',' expected");
800 for (++a
; *a
&& isspace(*a
); ++a
) ;
801 if (!a
[0]) { curLine
[0] = '\0'; return 0; }
802 memmove(curLine
, a
, strlen(a
)+1);
807 static void skipInstruction (void) {
811 for (cnt
= 1; cnt
> 0; --cnt
) {
812 while (*str
&& isspace(*str
)) ++str
; // skip spaces
813 while (*str
&& !isspace(*str
)) ++str
; // skip non-spaces
814 while (*str
&& isspace(*str
)) ++str
; // skip spaces
815 if (!str
[0] || *str
!= ':') break;
816 // try again if we have a colon
818 memmove(curLine
, str
, strlen(str
)+1);
822 ///////////////////////////////////////////////////////////////////////////////
825 static MAYBE_UNUSED
void removeSpacesAndColons (void) {
827 while (*ep
&& (isspace(*ep
) || *ep
== ':')) ++ep
;
828 memmove(curLine
, ep
, strlen(ep
)+1);
832 /* remove label from curLine */
833 static void removeLabel (void) {
836 if (ep
[0] && !isspace(ep
[0])) for (ep
= curLine
; *ep
&& !isspace(*ep
) && *ep
!= ':'; ++ep
) ; // skip text
837 // skip spaces and colons
838 while (*ep
&& (isspace(*ep
) || *ep
== ':')) ++ep
;
839 memmove(curLine
, ep
, strlen(ep
)+1);
843 static void processLabel (void) {
848 int noLocAff
= 0, doEQU
= 0;
850 memset(n2
, 0, sizeof(n2
));
851 if (!curLine
[0] || isspace(curLine
[0]) || curLine
[0] == ':') { removeLabel(); return; } // removeLabel() removes any spaces, etc
853 for (ep
= curLine
; *ep
&& !isspace(*ep
) && *ep
!= ':'; ++ep
) ;
854 if (ep
-curLine
> 120) fatal("label too long");
856 memset(n2
, 0, sizeof(n2
));
857 memmove(n2
, curLine
, ep
-curLine
);
858 if (!urIsValidLabelName(n2
)) return; // this is not a valid label, get out of here
859 // check if this can be instruction
860 while (*ep
&& isspace(*ep
)) ++ep
;
861 if (*ep
!= ':' && urFindOp(n2
)) return; // this must be and instruction, process it
862 // ok, we got a good label
864 if (n2
[0] == '@' && n2
[1]) { noLocAff
= 1; memmove(n2
, n2
+1, strlen(n2
)); }
865 nn
= fixGlobalLabel((ln
= fixLocalLabel(n2
)));
866 lbl
= urAddLabel(nn
);
868 lbl
->refLine
= curSrcLine
->lineNo
;
869 lbl
->refFile
= strdup(curSrcLine
->fname
);
871 //printf("new: [%s]\n", lbl->name);
873 if (curLine
[0] == '=') {
875 argstart
= curLine
+1;
878 argstart
= strIsCommand("EQU", curLine
);
880 if (!argstart
|| doEQU
) {
881 if (pass
== 0 && lbl
->type
!= -1) fatal("duplicate label %s", lbl
->name
);
885 memmove(curLine
, argstart
, strlen(argstart
)+1);
887 if (lbl
->type
!= -1 && lbl
->type
!= 0) fatal("duplicate label %s", lbl
->name
);
890 int32_t res
= getOneExprArg(&defined
);
896 if (pass
!= 0) fatal("can't calculate label %s", lbl
->name
);
902 if (lbl
->name
[0] != '{' && !noLocAff
) {
903 if (lastSeenGlobalLabel
) free(lastSeenGlobalLabel
);
904 lastSeenGlobalLabel
= strdup(lbl
->name
);
912 ///////////////////////////////////////////////////////////////////////////////
913 // instruction finder (in source)
915 /* array ends with NULL */
916 /* returns line or NULL */
917 /* iidx will be set to found instruction number */
918 static SourceLine
*findNextInstructionFromList (int *iidx
, ...) {
920 SourceLine
*cur
= curSrcLine
;
922 if (iidx
) *iidx
= -1;
923 for (; cur
; cur
= cur
->next
) {
925 //if (!isspace(cur->line[0])) continue; // fuck labeled strings
928 const char *name
= va_arg(ap
, const char *);
930 if (strIsCommand(name
, cur
->line
)) {
942 static MAYBE_UNUSED SourceLine
*findNextInstruction (const char *name
) {
943 return findNextInstructionFromList(NULL
, name
, NULL
);
947 ///////////////////////////////////////////////////////////////////////////////
950 static int optRunSNA
= 1;
951 static int optRunTape
= 1;
952 static int optTapExt
= 0; /* set '.tap' extension (but don't write tape; this for inline tape blocks) */
955 /* return 'found' flag */
956 static int findChunkFrom (int addr
, int *start
, int *len
) {
957 if (addr
< 0) addr
= 0;
958 for (; addr
<= 65535 && !memused
[addr
]; ++addr
) ;
959 if (addr
> 65535) return 0;
961 for (; addr
<= 65535 && memused
[addr
]; ++addr
) ;
962 *len
= addr
-(*start
);
967 static void rleUnpack (uint16_t addr
, const uint8_t *buf
, int buflen
) {
968 for (; buflen
>= 2; buflen
-= 2) {
970 uint8_t byte
= *buf
++;
971 //printf("%d %u %u\n", cnt+1, byte, addr);
972 for (; cnt
>= 0; --cnt
, ++addr
) if (!memused
[addr
]) putByte(addr
, byte
);
977 static int fWriteByte (FILE *fo
, uint8_t b
, uint8_t *bxor
) {
978 if (fwrite(&b
, 1, 1, fo
) != 1) return -1;
979 if (bxor
) *bxor
= (*bxor
)^b
;
984 static int fWriteWord (FILE *fo
, uint16_t w
, uint8_t *bxor
) {
985 if (fWriteByte(fo
, w
&0xFFU
, bxor
)) return -1;
986 if (fWriteByte(fo
, (w
>>8)&0xFFU
, bxor
)) return -1;
991 ///////////////////////////////////////////////////////////////////////////////
994 static int saveSna (const char *fname
) {
995 char *fn
= malloc(strlen(fname
)+16);
999 sprintf(fn
, "%s.sna", fname
);
1000 fo
= fopen(fn
, "wb");
1002 if (!fo
) { fprintf(stderr
, "ERROR: can't write SNA file: %s.sna\n", fname
); return -1; }
1003 printf("out: %s.sna\n", fname
);
1004 memmove(regs
, ursna48
, 27);
1006 /* push new address */
1007 uint16_t sp
= (uint16_t)regs
[23]+(((uint16_t)regs
[24])<<8);
1009 putByte(sp
, ent
&0xFFU
);
1010 putByte(sp
+1, (ent
>>8)&0xFFU
);
1011 regs
[23] = sp
&0xFFU
;
1012 regs
[24] = (sp
>>8)&0xFFU
;
1014 fwrite(regs
, 27, 1, fo
);
1015 rleUnpack(16384, ursna48
+27, sizeof(ursna48
)-27);
1016 fwrite(memory
+16384, 49152, 1, fo
);
1022 ///////////////////////////////////////////////////////////////////////////////
1025 static void saveRaw (const char *basename
) {
1026 char *fname
= malloc(strlen(basename
)+16);
1030 while (findChunkFrom(start
, &start
, &len
)) {
1031 sprintf(fname
, "%s_%04X.%s", basename
, start
, optTapExt
?"tap":"bin");
1032 fo
= fopen(fname
, "wb");
1034 fprintf(stderr
, "ERROR: can't write file %s!\n", fname
);
1036 printf("out: %s\n", fname
);
1037 if (fwrite(memory
+start
, len
, 1, fo
) != 1) {
1038 fprintf(stderr
, "ERROR: error writing file %s!\n", fname
);
1051 ///////////////////////////////////////////////////////////////////////////////
1054 static void saveTapCargador (FILE *fo
) {
1056 static uint8_t cargador
[16384]; // should be enough for everyone
1057 int start
= 0, len
, pos
, f
;
1061 void putStr (const char *s
) {
1062 for (; *s
; ++s
) cargador
[pos
++] = *s
;
1065 void putNum (int num
) {
1067 sprintf(buf
, "%d", num
);
1074 cargador
[0] = 0; cargador
[1] = 10;
1075 // size (will be fixed later)
1076 putStr("\xfd\xb0\""); putNum(clrAddr
); putStr("\""); // CLEAR VAL "xxx"
1078 while (findChunkFrom(start
, &start
, &len
)) {
1080 putStr(":\xef\"\"\xaf");
1084 // :RANDOMIZE USR VAL "xxx"
1085 putStr(":\xf9\xc0\xb0\""); putNum(ent
); putStr("\"\r");
1087 cargador
[2] = (pos
-4)&0xff;
1088 cargador
[3] = ((pos
-4)>>8)&0xff;
1090 fWriteWord(fo
, 19, NULL
); // length of header
1092 fWriteByte(fo
, 0, &bxor
); // header block
1093 fWriteByte(fo
, 0, &bxor
); // 'basic' flag
1094 fWriteByte(fo
, 'c', &bxor
);
1095 fWriteByte(fo
, 'a', &bxor
);
1096 fWriteByte(fo
, 'r', &bxor
);
1097 fWriteByte(fo
, 'g', &bxor
);
1098 fWriteByte(fo
, 'a', &bxor
);
1099 fWriteByte(fo
, 'd', &bxor
);
1100 fWriteByte(fo
, 'o', &bxor
);
1101 fWriteByte(fo
, 'r', &bxor
);
1102 fWriteByte(fo
, ' ', &bxor
);
1103 fWriteByte(fo
, ' ', &bxor
);
1104 fWriteWord(fo
, pos
, &bxor
); // length
1105 fWriteWord(fo
, 10, &bxor
); // start
1106 fWriteWord(fo
, pos
, &bxor
); // length2
1107 fWriteByte(fo
, bxor
, NULL
);
1109 fWriteWord(fo
, pos
+2, NULL
); // plus type and checkbyte
1111 fWriteByte(fo
, 0xFFU
, &bxor
); // data block
1112 for (f
= 0; f
< pos
; ++f
) fWriteByte(fo
, cargador
[f
], &bxor
);
1113 fWriteByte(fo
, bxor
, NULL
);
1117 static void saveTap (const char *basename
) {
1118 char *fname
= malloc(strlen(basename
)+16);
1120 int start
= 0, len
, f
;
1124 sprintf(fname
, "%s.tap", basename
);
1125 fo
= fopen(fname
, "wb");
1127 if (!fo
) { fprintf(stderr
, "ERROR: can't write file %s.tap!\n", basename
); return; }
1128 printf("out: %s.tap\n", basename
);
1129 if (optRunTape
) saveTapCargador(fo
);
1130 while (findChunkFrom(start
, &start
, &len
)) {
1132 sprintf(blkname
, "c%04X:%04X", start
, len
);
1133 //printf(" block: %s\n", blkname);
1134 fWriteWord(fo
, 19, NULL
); // length of header
1136 fWriteByte(fo
, 0, &bxor
); // header block
1137 fWriteByte(fo
, 3, &bxor
); // 'code' flag
1138 for (f
= 0; f
< 10; ++f
) fWriteByte(fo
, blkname
[f
], &bxor
);
1139 fWriteWord(fo
, len
, &bxor
);
1140 fWriteWord(fo
, start
, &bxor
);
1141 fWriteWord(fo
, 32768, &bxor
);
1142 fWriteByte(fo
, bxor
, NULL
);
1144 fWriteWord(fo
, len
+2, NULL
); // plus type and checkbyte
1146 fWriteByte(fo
, 0xFFU
, &bxor
); // data block
1147 for (f
= 0; f
< len
; ++f
) fWriteByte(fo
, memory
[start
+f
], &bxor
);
1148 fWriteByte(fo
, bxor
, NULL
);
1154 ///////////////////////////////////////////////////////////////////////////////
1155 // pseudoinstructions
1157 // note that processCurrentLine() will NOT skip to the next line before
1158 // calling pseudoinstruction handler!
1159 // note that processCurrentLine() will skip current line after calling
1160 // pseudoinstruction handler!
1162 static int wasOrg
= 0;
1163 static int wasClr
= 0;
1166 ///////////////////////////////////////////////////////////////////////////////
1169 static void piDISPLAYX (int passNo
, int asHex
) {
1173 char *res
= getStrArg(&len
);
1174 if (passNo
< 0 || pass
== passNo
) printf("%s", res
);
1177 int32_t v
= getExprArg(&defined
);
1178 if (passNo
< 0 || pass
== passNo
) {
1179 if (asHex
) printf("%04X", (unsigned int)v
);
1180 else printf("%d", v
);
1183 if (!skipComma()) break;
1188 static void piDISPLAY (void) { piDISPLAYX(1, 0); }
1189 static void piDISPLAY0 (void) { piDISPLAYX(0, 0); }
1190 static void piDISPLAYA (void) { piDISPLAYX(-1, 0); }
1191 static void piDISPHEX (void) { piDISPLAYX(1, 1); }
1192 static void piDISPHEX0 (void) { piDISPLAYX(0, 1); }
1193 static void piDISPHEXA (void) { piDISPLAYX(-1, 1); }
1196 ///////////////////////////////////////////////////////////////////////////////
1199 static void piORG (void) {
1201 int32_t res
= getOneExprArg(&defined
);
1202 if (!defined
) fatal("sorry, ORG operand value must be known here");
1203 if (res
< 0 || res
> 65535) fatal("invalid ORG operand value: %d", res
);
1204 if (inTapeBlock
) fatal("sorry, no ORGs in TAPEDATA allowed");
1209 if (!wasClr
&& res
> 0) clrAddr
= res
-1;
1214 static void piDISP (void) {
1216 int32_t res
= getOneExprArg(&defined
);
1217 if (!defined
) fatal("sorry, DISP operand value must be known here");
1218 if (res
< 0 || res
> 65535) fatal("invalid DISP operand value: %d", res
);
1219 //printf("DISP=%d\n", res);
1224 static void piENDDISP (void) {
1225 if (inTapeBlock
) fatal("sorry, no ENDDISPs in TAPEDATA allowed");
1230 static void piENT (void) {
1232 int32_t res
= getOneExprArg(&defined
);
1233 //if (!defined) fatal("sorry, ENT operand value must be known here");
1234 if (res
< 0 || res
> 65535) fatal("invalid ENT operand value: %d", res
);
1239 static void piCLR (void) {
1241 int32_t res
= getOneExprArg(&defined
);
1242 //if (!defined) fatal("sorry, CLR operand value must be known here");
1243 if (res
< 0 || res
> 65535) fatal("invalid CLR operand value: %d", res
);
1249 static void piRESERVE (void) {
1251 int defined = 1, start;
1252 int32_t res = getExprArg(&defined);
1253 if (!defined) fatal("sorry, RESERVE operand values must be known here");
1254 if (res < 0 || res > 65535) fatal("invalid RESERVE operand value: %d", res);
1256 if (!skipComma()) fatal("RESERVE needs 2 args");
1257 res = getOneExprArg(&defined);
1258 if (!defined) fatal("sorry, RESERVE operand values must be known here");
1259 if (res < 0 || res > 65535) fatal("invalid RESERVE operand value: %d", res);
1260 for (; len > 0; --len, start = (start+1)&0xffff) memresv[start] = 1;
1262 fatal("RESERVE: not yet!");
1266 static void piALIGN (void) {
1268 if (inTapeBlock
) fatal("sorry, no ALIGNs in TAPEDATA allowed");
1269 int32_t res
= getOneExprArg(&defined
);
1270 if (!defined
) fatal("sorry, ALIGN operand value must be known here");
1271 if (res
< 0 || res
> 65535) fatal("invalid ALIGN operand value: %d", res
);
1272 if (pc
!= disp
) fatal("sorry, no ALIGNs in desynced blocks allowed");
1273 if (res
> 0 && pc
%res
!= 0) {
1282 static void piDISPALIGN (void) {
1284 int32_t res
= getOneExprArg(&defined
);
1285 if (!defined
) fatal("sorry, DISPALIGN operand value must be known here");
1286 if (res
< 0 || res
> 65535) fatal("invalid DISPALIGN operand value: %d", res
);
1287 if (res
> 0 && disp
%res
!= 0) {
1295 ///////////////////////////////////////////////////////////////////////////////
1298 static int defIncr
= 0;
1301 static void piDEFINCR (void) {
1303 int32_t cnt
= getOneExprArg(&defined
);
1304 if (!defined
) fatal("DEFINCR: increment must be defined");
1309 static void piDEFBW (int isWord
) {
1314 char *res
= getStrArg(&len
);
1315 for (f
= 0; f
< len
; ++f
) {
1316 int32_t b
= (uint8_t)res
[f
];
1318 if (b
< -128 || b
> 255) fatal("invalid operand value: %d", b
);
1319 if (b
< 0) b
+= 256;
1323 int32_t res
= getExprArg(&defined
);
1324 if (pass
> 0 && !defined
) fatal("undefined operand");
1327 if (res
< -32768 || res
> 65535) fatal("invalid operand value: %d", res
);
1328 if (res
< 0) res
+= 65536;
1329 if (isWord
== 1) emitWord(res
); else emitRWord(res
);
1331 if (res
< -128 || res
> 255) fatal("invalid operand value: %d", res
);
1332 if (res
< 0) res
+= 256;
1336 if (!skipComma()) break;
1340 static void piDEFB (void) { piDEFBW(0); }
1341 static void piDEFW (void) { piDEFBW(1); }
1342 static void piDEFR (void) { piDEFBW(2); }
1345 static void piDEFS (void) {
1349 int32_t res
= getExprArg(&defined
);
1350 if (pass
> 0 && !defined
) fatal("undefined operand");
1351 if (res
< 1 || res
> 65535) fatal("invalid number of repetitions: %d", res
);
1352 if (*curLine
&& curLine
[0] == ',') {
1354 bt
= getExprArg(&defined
);
1355 if (pass
> 0 && !defined
) fatal("undefined operand");
1357 if (bt
< -128 || bt
> 255) fatal("invalid operand value: %d", res
);
1358 if (bt
< 0) bt
+= 256;
1359 for (f
= 0; f
< res
; ++f
) emitByte(bt
);
1361 pc
+= res
; disp
+= res
;
1363 if (!skipComma()) break;
1368 /* bit 0: put '\0' */
1369 /* bit 1: set bit 7 of last byte */
1370 /* bit 2: put length */
1371 static void piDEFSTR (int type
) {
1375 char *res
= getStrArg(&len
);
1377 if (len
> 255) fatal("string too long");
1380 for (f
= 0; f
< len
; ++f
) {
1381 uint8_t b
= (uint8_t)res
[f
];
1382 if ((type
&0x02) && f
== len
-1) b
|= 0x80;
1385 if (type
&0x01) emitByte(0);
1388 int32_t v
= getExprArg(&defined
);
1389 if (pass
> 0 && !defined
) fatal("undefined expression");
1390 if (!defined
) v
= 0; else v
+= defIncr
;
1391 if (v
< -128 || v
> 255) fatal("invalid operand value: %d", v
);
1392 if (v
< 0) v
+= 256;
1395 if (!skipComma()) break;
1400 static void piDEFM (void) { piDEFSTR(0x00); }
1401 static void piDEFZ (void) { piDEFSTR(0x01); }
1402 static void piDEFX (void) { piDEFSTR(0x02); }
1403 static void piDEFC (void) { piDEFSTR(0x04); }
1406 ///////////////////////////////////////////////////////////////////////////////
1409 /* INCBIN "name"[,maxlen] */
1410 static void piINCBIN (void) {
1416 char *args
= curLine
;
1418 if (!curLine
[0]) fatal("INCBIN without file name");
1422 } else if (curLine
[0] == '<') {
1429 fn
= parseStr(&args
, qCh
, NULL
); // i don't care about string length here
1430 if (!fn
[0]) fatal("INCBIN: empty file name");
1431 memmove(curLine
, args
, strlen(args
)+1);
1433 if (curLine
[0] == ',') {
1436 maxlen
= getOneExprArg(&defined
);
1437 if (!defined
) fatal("INCBIN: undefined maxlen");
1438 if (maxlen
< 1) return; // nothing to do
1442 sprintf(curLine
, "%s/%s", sysIncludeDir
, fn
);
1444 sprintf(curLine
, "%s", fn
);
1447 fl
= fopen(curLine
, "rb");
1448 if (!fl
) fatal("INCBIN: file not found: %s", curLine
);
1449 while (maxlen
-- > 0) {
1450 int res
= fread(&bt
, 1, 1, fl
);
1452 if (res
!= 1) { fclose(fl
); fatal("INCBIN: error reading file: %s", curLine
); }
1459 ///////////////////////////////////////////////////////////////////////////////
1460 // MODULE, ENDMODULE
1462 static void piENDMODULE (void) {
1463 if (!curModule
) fatal("ENDMODULE without MODULE");
1465 char *mn
= getOneLabelArg();
1466 if (strcmp(mn
, curModule
->name
)) fatal("invalid module name in ENDMODULE: %s", mn
);
1472 static void piMODULE (void) {
1475 SourceLine
*ol
= curSrcLine
;
1478 if (curModule
) fatal("no nested modules allowed");
1479 mn
= getOneLabelArg();
1480 if (!urIsValidLabelName(mn
)) fatal("invalid module name: %s", mn
);
1481 mi
= moduleFind(mn
);
1482 //printf("[%s] %p\n", mn, mi);
1485 if (strcmp(mi
->fname
, curSrcLine
->fname
)) fatal("duplicate module definition; previous was in %s", mi
->fname
);
1487 nextSrcLine(); // skip ourself
1488 if (!setCurSrcLine(findNextInstructionFromList(&inum
, "MODULE", "ENDMODULE", NULL
))) {
1490 fatal("no ENDMODULE");
1492 if (inum
== 0) fatal("no nested modules allowed");
1499 mi
= moduleAdd(mn
, curSrcLine
->fname
);
1506 ///////////////////////////////////////////////////////////////////////////////
1509 static void piEDUP (void) {
1510 fatal("EDUP without DUP");
1514 static void piDUP (void) {
1515 int defined
= 1, dupCnt
= 1, inum
;
1516 SourceLine
*stline
, *eline
= NULL
;
1517 int32_t cnt
= getOneExprArg(&defined
);
1518 if (!defined
) fatal("DUP: counter must be defined");
1519 if (cnt
> 65535) fatal("DUP: counter too big: %d", cnt
);
1520 if (cnt
< 0) warningMsg("DUP: counter too small: %d", cnt
);
1521 // now find corresponding EDUP
1522 // note that we should skip nested DUPs
1523 nextSrcLine(); // skip ourself
1524 stline
= curSrcLine
;
1525 while (curSrcLine
) {
1526 if (!setCurSrcLine(findNextInstructionFromList(&inum
, "DUP", "EDUP", NULL
))) break;
1527 // ok, we found something; what is it?
1531 nextSrcLine(); // skip DUP
1534 if (--dupCnt
== 0) {
1539 nextSrcLine(); // skip EDUP
1542 if (!eline
) { setCurSrcLine(stline
); fatal("no EDUP"); }
1543 // now repeat that lines
1545 setCurSrcLine(stline
);
1546 while (curSrcLine
!= eline
) processCurrentLine();
1551 ///////////////////////////////////////////////////////////////////////////////
1554 static int ifCount
= 0;
1557 static int ifSkipToEndIfOrElse (int wholeBody
) {
1558 int inum
, wasElse
= 0;
1561 while (curSrcLine
) {
1562 if (!setCurSrcLine(findNextInstructionFromList(&inum
, "IF", "ELSE", "ENDIF", "ELSEIF", "MACRO", "ENDM", "IFX", "ELSEIFX", NULL
))) break;
1566 nextSrcLine(); // skip IF
1567 ifSkipToEndIfOrElse(1); // and recurse
1568 nextSrcLine(); // skip ENDIF
1571 if (wasElse
) fatal("duplicate ELSE");
1572 if (!wholeBody
) return 1;
1574 nextSrcLine(); // skip ELSE
1575 break; // and continue
1577 return 0; // and exit
1580 if (wasElse
) fatal("ELSEIF in ELSE");
1581 if (!wholeBody
) return 2;
1582 nextSrcLine(); // skip ELSEIF
1583 break; // and continue
1585 // skip it as a whole
1586 nextSrcLine(); // skip MACRO
1589 if (!setCurSrcLine(findNextInstructionFromList(&inum
, "MACRO", "ENDM", NULL
))) { setCurSrcLine(oline
); fatal("invalid MACRO"); }
1590 if (inum
== 1) break;
1591 fatal("invalid nested MACRO");
1593 nextSrcLine(); // skip ENDM
1596 fatal("unexpected ENDM");
1599 fatal("IF without ENDIF");
1604 static void piENDIF (void) {
1605 if (--ifCount
< 0) fatal("ENDIF without IF");
1609 static void piELSE (void) {
1610 if (--ifCount
< 0) fatal("ELSE without IF");
1611 nextSrcLine(); // skip ELSE
1612 ifSkipToEndIfOrElse(1);
1616 static void piELSEIF (void) {
1617 if (--ifCount
< 0) fatal("ELSEIF without IF");
1618 nextSrcLine(); // skip ELSEIF
1619 ifSkipToEndIfOrElse(1);
1623 static void piIFAll (int isIfX
) {
1625 int ooo
= lblOptMakeU2
;
1626 lblOptMakeU2
= isIfX
? 1 : 0;
1627 int32_t cond
= getOneExprArg(&defined
);
1630 if (!isIfX
) fatal("IF: condition must be defined");
1631 cond
= 0; // for IFX: 0 is there is any undefined label
1634 // ok, do it until ELSE/ELSEIF/ENDIF
1642 nextSrcLine(); // skip last instruction
1643 // skip until ELSE/ELSEIF/ENDIF
1644 r
= ifSkipToEndIfOrElse(0);
1645 if (r
== 0) break; // ENDIF
1646 if (r
== 1) { ++ifCount
; break; } // ELSE
1647 // ELSEIF, do condition
1648 if ((args
= strIsCommand("ELSEIF", curLine
)) == NULL
) fatal("internal error in conditionals"); // the thing that should not be
1649 memmove(curLine
, args
, strlen(args
)+1);
1650 cond
= getOneExprArg(&defined
);
1651 if (!defined
) fatal("ELSEIF: condition must be defined");
1652 if (cond
) { ++ifCount
; break; } // condition is true
1657 static void piIF (void) { piIFAll(0); }
1658 static void piIFX (void) { piIFAll(1); }
1661 ///////////////////////////////////////////////////////////////////////////////
1664 * what i did with MACRO is the brain-damaged cheating all the way.
1665 * first, i will collect the MACRO body and remember it.
1666 * second, when the macro is used, i will:
1667 * * create unique labels for all supplied macro args, each with
1668 * number (so IFARG/IFNARG can check the existance)
1669 * * insert the whole macro body in place, fixing argument refs
1670 * * let the asm play with it
1671 * another tricky part is 'local labels': i have to change all
1672 * '..lbl' references -- generate new label name for it and
1673 * replace all refs. and be careful to not touch the strings.
1674 * this is not the best scheme, but it is fairly simple and it wokrs.
1676 static void piMACRO (void) {
1677 fatal("sorry, no MACRO yet");
1681 static void piENDM (void) {
1682 fatal("ENDM withoud MACRO");
1686 ///////////////////////////////////////////////////////////////////////////////
1688 static int optWriteType
= 't';
1689 static int optWTChanged
= 0;
1692 static void piDEFFMT (void) {
1697 name
= getOneStrArg(&len
);
1699 name
= getOneLabelArg();
1701 if (optWTChanged
) return;
1702 if (!strcasecmp(name
, "SNA")) {
1708 if (!strcasecmp(name
, "RUNSNA")) {
1714 if (!strcasecmp(name
, "TAP") || !strcasecmp(name
, "TAPE")) {
1720 if (!strcasecmp(name
, "RUNTAP") || !strcasecmp(name
, "RUNTAPE")) {
1726 if (!strcasecmp(name
, "BIN") || !strcasecmp(name
, "RAW")) {
1732 if (!strcasecmp(name
, "NONE") || !strcasecmp(name
, "NOTHING")) {
1738 fatal("invalid default output type: %s", name
);
1742 ///////////////////////////////////////////////////////////////////////////////
1745 static void processCurrentLine (void) {
1746 char *str
, *ee
, name
[66];
1749 if (!curSrcLine
) return; // do nothing
1752 // try to find and process command
1753 str
= curLine
; while (*str
&& isspace(*str
)) ++str
; // skip spaces
1755 for (ee
= str
; *ee
&& !isspace(*ee
) && *ee
!= '"' && *ee
!= '\''; ++ee
) ;
1756 // get command, if any
1757 if (ee
!= str
&& ee
-str
<= 64) {
1758 memset(name
, 0, sizeof(name
));
1759 memmove(name
, str
, ee
-str
);
1761 op
= urFindOp(name
);
1764 str
= ee
; while (*str
&& isspace(*str
)) ++str
; // skip spaces
1765 memmove(curLine
, str
, strlen(str
)+1);
1767 nextSrcLine(); // skip it
1771 // try to compile this
1775 // skip spaces and ':'
1776 str
= curLine
; while (*str
&& (isspace(*str
) || *str
== ':')) ++str
;
1777 memmove(curLine
, str
, strlen(str
)+1);
1778 if (!curLine
[0]) break;
1780 len
= urAssembleOne(curLine
, pc
, disp
, &errpos
);
1781 if (len
< 0) fatalUrLib(len
);
1782 pc
+= len
; disp
+= len
;
1783 if (len
>= 0 && errpos
) {
1784 memmove(curLine
, errpos
+1, strlen(errpos
));
1789 nextSrcLine(); // skip it
1793 ///////////////////////////////////////////////////////////////////////////////
1794 // setup instructions
1796 static void registerInstructions (void) {
1797 urAddOp("DISPLAY", piDISPLAY
);
1798 urAddOp("DISPLAY0", piDISPLAY0
);
1799 urAddOp("DISPLAYA", piDISPLAYA
);
1800 urAddOp("DISPHEX", piDISPHEX
);
1801 urAddOp("DISPHEX0", piDISPHEX0
);
1802 urAddOp("DISPHEXA", piDISPHEXA
);
1804 urAddOp("DEFFMT", piDEFFMT
);
1806 urAddOp("MACRO", piMACRO
);
1807 urAddOp("ENDM", piENDM
);
1809 urAddOp("ORG", piORG
);
1810 urAddOp("DISP", piDISP
);
1811 urAddOp("ENDDISP", piENDDISP
);
1812 urAddOp("PHASE", piDISP
);
1813 urAddOp("DEPHASE", piENDDISP
);
1814 urAddOp("UNPHASE", piENDDISP
);
1815 urAddOp("ALIGN", piALIGN
);
1816 urAddOp("DISPALIGN", piDISPALIGN
);
1817 urAddOp("PHASEALIGN", piDISPALIGN
);
1818 urAddOp("ENT", piENT
);
1819 urAddOp("CLR", piCLR
);
1820 urAddOp("RESERVE", piRESERVE
);
1822 urAddOp("INCBIN", piINCBIN
);
1824 urAddOp("MODULE", piMODULE
);
1825 urAddOp("ENDMODULE", piENDMODULE
);
1827 urAddOp("DUP", piDUP
);
1828 urAddOp("EDUP", piEDUP
);
1830 urAddOp("IF", piIF
);
1831 urAddOp("IFX", piIFX
);
1832 urAddOp("ELSE", piELSE
);
1833 urAddOp("ELSEIF", piELSEIF
);
1834 urAddOp("ELSEIFX", piELSEIF
);
1835 urAddOp("ENDIF", piENDIF
);
1837 urAddOp("DEFINCR", piDEFINCR
);
1838 urAddOp("DEFB", piDEFB
); urAddOp("DB", piDEFB
);
1839 urAddOp("DEFW", piDEFW
); urAddOp("DW", piDEFW
);
1840 urAddOp("DEFR", piDEFR
); urAddOp("DR", piDEFR
);
1841 urAddOp("DEFS", piDEFS
); urAddOp("DS", piDEFS
);
1842 urAddOp("DEFM", piDEFM
); urAddOp("DM", piDEFM
);
1843 urAddOp("DEFZ", piDEFZ
); urAddOp("DZ", piDEFZ
);
1844 urAddOp("DEFX", piDEFX
); urAddOp("DX", piDEFX
);
1845 urAddOp("DEFC", piDEFC
); urAddOp("DC", piDEFC
);
1849 ///////////////////////////////////////////////////////////////////////////////
1850 // preparing another pass
1852 static void initPass (void) {
1853 curSrcLine
= asmText
;
1855 pc
= disp
= ent
= 0x100; // viva CP/M!
1863 lastSeenGlobalLabel
= strdup(" [MAIN] ");
1869 static int posstPass (void) {
1870 if (lastSeenGlobalLabel
) free(lastSeenGlobalLabel
); lastSeenGlobalLabel
= NULL
;
1871 if (checkLabels()) return -1;
1872 if (ifCount
!= 0) fatal("unbalanced IFs");
1877 ///////////////////////////////////////////////////////////////////////////////
1880 static struct option longOpts
[] = {
1881 {"sna", 0, NULL
, 's'},
1882 {"autosna", 0, NULL
, 'S'},
1883 {"tap", 0, NULL
, 't'},
1884 {"autotap", 0, NULL
, 'T'},
1885 /*{"rawtap", 0, NULL, 'T'},*/
1886 {"raw", 0, NULL
, 'r'},
1887 /*{"dmb", 0, NULL, 'b'},*/
1888 {"none", 0, NULL
, 'n'},
1889 {"help", 0, NULL
, 'h'},
1894 static const char *defInFiles
[] = {"main.zas", "main.a80", "main.asm", NULL
};
1897 static void usage (const char *pname
) {
1899 /*" -T --rawtap write raw file with '.tap' extension\n"*/
1900 /*" -b --dmb write .dmb file\n"*/
1902 "usage: %s [options] infile\n"
1903 "default infiles:", pname
);
1904 for (f
= 0; defInFiles
[f
]; ++f
) printf(" %s", defInFiles
[f
]);
1907 " -s --sna write 48K .SNA file\n"
1908 " -S --autosna write 48K .SNA file with autostart\n"
1909 " -t --tap write .tap file\n"
1910 " -T --autotap write .tap file with basic loader (CLR to set CLEAR)\n"
1911 " -r --raw write raw file(s)\n"
1912 " -n --none write nothing\n"
1913 " -h --help this help\n");
1917 ///////////////////////////////////////////////////////////////////////////////
1920 int main (int argc
, char *argv
[]) {
1922 const char *pname
= argv
[0];
1923 char *inFile
= NULL
;
1926 urGetByte
= getByte
;
1927 urPutByte
= putByte
;
1928 urFindLabelByName
= findLabelCB
;
1929 urIsLabelDefinedOrKnown
= isLabelDefinedOrKnown
;
1931 printf("urasm v%d.%d.%d, compile date: %s %s\n", VERSION_HI
, VERSION_MID
, VERSION_LO
, __DATE__
, __TIME__
);
1932 while ((c
= getopt_long(argc
, argv
, "sStTrnh", longOpts
, NULL
)) >= 0) {
1934 case 'S': optRunSNA
= 1; optWriteType
= 's'; optWTChanged
= 1; break;
1935 case 's': optRunSNA
= 0; optWriteType
= 's'; optWTChanged
= 1; break;
1936 case 'T': optRunTape
= 1; optWriteType
= 't'; optWTChanged
= 1; break;
1937 case 't': optRunTape
= 0; optWriteType
= 't'; optWTChanged
= 1; break;
1938 case 'r': case 'n': optWriteType
= c
; optWTChanged
= 1; break;
1939 case 'h': usage(pname
); res
= 0; goto earlyerrquit
;
1943 if (optind
>= argc
) {
1944 // try to find default input file
1946 for (f
= 0; defInFiles
[f
]; ++f
) {
1947 if (!access(defInFiles
[f
], R_OK
)) {
1948 inFile
= strdup(defInFiles
[f
]);
1953 inFile
= strdup(argv
[optind
]);
1955 if (!inFile
|| !inFile
[0]) {
1957 fprintf(stderr
, "ERROR: no input file!\n");
1961 registerInstructions();
1963 res
= asmTextLoad(inFile
);
1966 printf("dumping...\n");
1967 FILE *fo = fopen("z000.out", "w");
1970 for (c = asmText; c; c = c->next) fprintf(fo, "%s ; %s: %d\n", c->line, c->fname, c->lineNo);
1974 for (pass
= 0; pass
<= 1; ++pass
) {
1976 printf("pass %d\n", pass
);
1977 setCurSrcLine(asmText
);
1978 if (setjmp(errJP
)) { res
= 1; break; }
1979 while (curSrcLine
) processCurrentLine();
1980 if (posstPass()) { res
= 1; break; }
1984 char *oc
= strdup(inFile
);
1985 char *pd
= strrchr(oc
, '.');
1986 if (pd
&& !strchr(oc
, '/')) *pd
= '\0';
1987 switch (optWriteType
) {
1988 case 's': saveSna(oc
); break;
1989 case 't': saveTap(oc
); break;
1990 case 'r': saveRaw(oc
); break;
1995 fprintf(stderr
, "ERROR: loading error!\n");
1998 if (lastSeenGlobalLabel
) free(lastSeenGlobalLabel
);
2004 if (inFile
) free(inFile
);
2005 if (sysIncludeDir
) free(sysIncludeDir
);