--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// 68KGEN.C - Tool to Generate 68000 Opcode Table
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#define EOS '\0'
+
+int kwnum = 1; /* current op# for kwgen output */
+
+FILE *kfp; /* keyword file */
+
+int lineno = 0;
+
+void error(char *, char *);
+void procln(int, char **);
+
+void main(int argc, char **argv) {
+ char *namv[256];
+ char *s;
+ int namcnt;
+ char ln[256];
+
+ if (argc == 2)
+ if ((kfp = fopen(argv[1], "w")) == NULL)
+ error("Cannot create: %s", argv[1]);
+
+ while (gets(ln) != NULL)
+ {
+ ++lineno; /* bump line# */
+ if (*ln == '#') /* ignore comments */
+ continue;
+
+ /*
+ * Tokenize line (like the way "argc, argv" works)
+ * and pass it to the parser.
+ */
+ namcnt = 0;
+ s = ln;
+ while (*s)
+ if (isspace(*s))
+ ++s;
+ else
+ {
+ namv[namcnt++] = s;
+ while (*s && !isspace(*s))
+ ++s;
+ if (isspace(*s))
+ *s++ = EOS;
+ }
+
+ if (namcnt)
+ procln(namcnt, namv);
+ }
+}
+
+
+/*
+ * Parse line
+ */
+void procln(int namc, char **namv) {
+ int i, j;
+ char *s;
+
+ if (namc == 1) /* alias for previous entry */
+ {
+ fprintf(kfp, "%s\t%d\n", namv[0], kwnum-1+1000);
+ return;
+ }
+
+ if (namc < 5)
+ {
+ fprintf(stderr, "%d: missing fields\n", lineno);
+ exit(1);
+ }
+
+ if (*namv[0] != '-') /* output keyword name */
+ fprintf(kfp, "%s\t%d\n", namv[0], kwnum + 1000);
+
+ printf("/*%4d %-6s*/ {", kwnum, namv[0]);
+
+ if (*namv[1] == '!')
+ printf("CGSPECIAL");
+ else for (s = namv[1], i=0; *s; ++s)
+ printf("%sSIZ%c", (i++ ? "|" : ""), *s);
+ printf(", %s, %s, ", namv[2], namv[3]);
+
+ if (*namv[4] == '%') /* enforce little fascist percent signs */
+ {
+ for (i=1, j=0; i < 17; ++i)
+ {
+ j <<= 1;
+ if (namv[4][i] == '1' ||
+ isupper(namv[4][i]))
+ ++j;
+ }
+ printf("0x%04x, ", j);
+ }
+ else printf("%s, ", namv[4]);
+
+ if (namc == 7 &&
+ *namv[6] == '+')
+ printf("%d, ", kwnum+1);
+ else printf("0, ");
+
+ printf("%s},\n", namv[5]);
+
+ ++kwnum;
+}
+
+void error(char *s, char *s1) {
+ fprintf(stderr, s, s1);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
--- /dev/null
+abcd 1001
+add 1003
+adda 1005
+addi 1006
+addq 1007
+addx 1008
+and 1010
+andi 1012
+asl 1015
+asr 1019
+bcc 1023
+bhs 1023
+bcs 1024
+blo 1024
+beq 1025
+bze 1025
+bz 1025
+bge 1026
+bgt 1027
+bhi 1028
+ble 1029
+bls 1030
+blt 1031
+bmi 1032
+bne 1033
+bnz 1033
+bpl 1034
+bvc 1035
+bvs 1036
+bchg 1037
+bclr 1041
+bra 1045
+bt 1045
+bset 1046
+bsr 1050
+btst 1051
+chk 1055
+clr 1056
+cmp 1058
+cmpa 1060
+cmpi 1061
+cmpm 1062
+dbcc 1063
+dbcs 1064
+dblo 1064
+dbeq 1065
+dbze 1065
+dbf 1066
+dbra 1066
+dbge 1067
+dbgt 1068
+dbhi 1069
+dbhs 1069
+dble 1070
+dbls 1071
+dblt 1072
+dbmi 1073
+dbne 1074
+dbnz 1074
+dbpl 1075
+dbt 1076
+dbvc 1077
+dbvs 1078
+divs 1079
+divu 1080
+eor 1081
+eori 1082
+exg 1085
+ext 1086
+illegal 1088
+jmp 1089
+jsr 1090
+lea 1091
+link 1092
+lsl 1093
+lsr 1097
+move 1101
+movea 1108
+movem 1109
+movep 1110
+moveq 1112
+muls 1113
+mulu 1114
+nbcd 1115
+neg 1116
+negx 1117
+nop 1118
+not 1119
+or 1120
+ori 1122
+pea 1125
+reset 1126
+rol 1127
+ror 1131
+roxl 1135
+roxr 1139
+rte 1143
+rtr 1144
+rts 1145
+sbcd 1146
+scc 1148
+shs 1148
+scs 1149
+slo 1149
+seq 1150
+sze 1150
+sf 1151
+sge 1152
+sgt 1153
+shi 1154
+sle 1155
+sls 1156
+slt 1157
+smi 1158
+sne 1159
+snz 1159
+spl 1160
+st 1161
+svc 1162
+svs 1163
+stop 1164
+sub 1165
+suba 1167
+subi 1168
+subq 1169
+subx 1170
+swap 1172
+tas 1173
+trap 1174
+trapv 1175
+tst 1176
+unlk 1177
--- /dev/null
+abcd NB M_DREG M_DREG %1100rrr100000rrr m_abcd +
+- NB M_APREDEC M_APREDEC %1100rrr100001rrr m_abcd
+
+add NBWL C_ALL M_DREG %1101rrr0sseR1100 m_ea +
+- NBWL M_DREG C_ALTMEM %1101rrr1sseR0101 m_ea +
+adda NWL C_ALL M_AREG %1101rrrs11eeeeee m_adda +
+addi NWBL M_IMMED C_ALTDATA %00000110sseeeS11 m_ea
+
+addq NBWL M_IMMED C_ALT %0101ddd0sseeeeee m_addq
+
+addx NBWL M_DREG M_DREG %1101rrr1ss000rrS m_abcd +
+- NBWL M_APREDEC M_APREDEC %1101rrr1ss001rrS m_abcd
+
+and NBWL C_DATA M_DREG %1100rrr0sseR1S00 m_ea +
+- NBWL M_DREG C_ALTMEM %1100rrr1sseR0S01 m_ea +
+andi NBWL M_IMMED C_ALTDATA %00000010sseeeS11 m_ea +
+- NB M_IMMED M_AM_CCR %0000001000111100 m_imm8 +
+- NW M_IMMED M_AM_SR %0000001001111100 m_imm
+
+asl NBWL M_DREG M_DREG %1110rrr1ss100rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc1ss000rrr m_shi +
+- NBWL M_DREG M_AM_NONE %11100011ss000rrS m_reg +
+- NW C_ALTMEM M_AM_NONE %1110000111eee000 m_ea
+
+asr NBWL M_DREG M_DREG %1110rrr0ss100rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc0ss000rrr m_shi +
+- NBWL M_DREG M_AM_NONE %11100010ss000rrS m_reg +
+- NW C_ALTMEM M_AM_NONE %1110000011eee000 m_ea
+
+bcc NBW C_LABEL M_AM_NONE %01100100bbbbbbbb m_br
+bhs
+bcs NBW C_LABEL M_AM_NONE %01100101bbbbbbbb m_br
+blo
+beq NBW C_LABEL M_AM_NONE %01100111bbbbbbbb m_br
+bze
+bz
+bge NBW C_LABEL M_AM_NONE %01101100bbbbbbbb m_br
+bgt NBW C_LABEL M_AM_NONE %01101110bbbbbbbb m_br
+bhi NBW C_LABEL M_AM_NONE %01100010bbbbbbbb m_br
+ble NBW C_LABEL M_AM_NONE %01101111bbbbbbbb m_br
+bls NBW C_LABEL M_AM_NONE %01100011bbbbbbbb m_br
+blt NBW C_LABEL M_AM_NONE %01101101bbbbbbbb m_br
+bmi NBW C_LABEL M_AM_NONE %01101011bbbbbbbb m_br
+bne NBW C_LABEL M_AM_NONE %01100110bbbbbbbb m_br
+bnz
+bpl NBW C_LABEL M_AM_NONE %01101010bbbbbbbb m_br
+bvc NBW C_LABEL M_AM_NONE %01101000bbbbbbbb m_br
+bvs NBW C_LABEL M_AM_NONE %01101001bbbbbbbb m_br
+
+bchg NL M_DREG M_DREG %0000rrr101eeeeee m_bitop +
+- NB M_DREG C_ALTDATA %0000rrr101eeeeee m_bitop +
+- NL M_IMMED M_DREG %0000100001eeeeee m_bitop +
+- NB M_IMMED C_ALTDATA %0000100001eeeeee m_bitop
+
+bclr NL M_DREG M_DREG %0000rrr110eeeeee m_bitop +
+- NB M_DREG C_ALTDATA %0000rrr110eeeeee m_bitop +
+- NL M_IMMED M_DREG %0000100010eeeeee m_bitop +
+- NB M_IMMED C_ALTDATA %0000100010eeeeee m_bitop
+
+bra NBW C_LABEL M_AM_NONE %01100000bbbbbbbb m_br
+bt
+
+bset NL M_DREG M_DREG %0000rrr111eeeeee m_bitop +
+- NB M_DREG C_ALTDATA %0000rrr111eeeeee m_bitop +
+- NL M_IMMED M_DREG %0000100011eeeeee m_bitop +
+- NB M_IMMED C_ALTDATA %0000100011eeeeee m_bitop
+
+bsr NBW C_LABEL M_AM_NONE %01100001bbbbbbbb m_br
+
+btst NL M_DREG M_DREG %0000rrr100eeeeee m_bitop +
+- NB M_DREG C_DATA %0000rrr100eeeeee m_bitop +
+- NL M_IMMED M_DREG %0000100000eeeeee m_bitop +
+- NB M_IMMED C_DATA-M_IMMED %0000100000eeeeee m_bitop
+
+chk NW C_DATA M_DREG %0100rrr110eR1000 m_ea
+
+clr NBWL C_ALTDATA M_AM_NONE %01000010sseeeS00 m_ea +
+- NWL M_AREG M_AM_NONE %1001rrrs11001rrr m_clra
+
+cmp NWL M_AREG M_DREG %1011rrr0sseR1S00 m_ea +
+- NBWL C_ALL M_DREG %1011rrr0sseR1S00 m_ea +
+cmpa NWL C_ALL M_AREG %1011rrrs11eeeeee m_adda +
+cmpi NBWL M_IMMED C_ALTDATA %00001100sseeeS11 m_ea +
+cmpm NBWL M_APOSTINC M_APOSTINC %1011xxx1ss001yRS m_reg
+
+dbcc NW M_DREG C_LABEL %0101010011001rrr m_dbra
+dbcs NW M_DREG C_LABEL %0101010111001rrr m_dbra
+dblo
+dbeq NW M_DREG C_LABEL %0101011111001rrr m_dbra
+dbze
+dbf NW M_DREG C_LABEL %0101000111001rrr m_dbra
+dbra
+dbge NW M_DREG C_LABEL %0101110011001rrr m_dbra
+dbgt NW M_DREG C_LABEL %0101111011001rrr m_dbra
+dbhi NW M_DREG C_LABEL %0101001011001rrr m_dbra
+dbhs
+dble NW M_DREG C_LABEL %0101111111001rrr m_dbra
+dbls NW M_DREG C_LABEL %0101001111001rrr m_dbra
+dblt NW M_DREG C_LABEL %0101110111001rrr m_dbra
+dbmi NW M_DREG C_LABEL %0101101111001rrr m_dbra
+dbne NW M_DREG C_LABEL %0101011011001rrr m_dbra
+dbnz
+dbpl NW M_DREG C_LABEL %0101101011001rrr m_dbra
+dbt NW M_DREG C_LABEL %0101000011001rrr m_dbra
+dbvc NW M_DREG C_LABEL %0101100011001rrr m_dbra
+dbvs NW M_DREG C_LABEL %0101100111001rrr m_dbra
+
+divs NW C_DATA M_DREG %1000rrr111eR1000 m_ea
+
+divu NW C_DATA M_DREG %1000rrr011eR1000 m_ea
+
+eor NBWL M_DREG C_ALTDATA %1011rrr1sseR0S01 m_ea +
+eori NBWL M_IMMED C_ALTDATA %00001010sseeeS11 m_ea +
+- NB M_IMMED M_AM_CCR %0000101000111100 m_imm8 +
+- NW M_IMMED M_AM_SR %0000101001111100 m_imm
+
+exg NL M_DREG|M_AREG M_DREG|M_AREG %1100rrr1ooooorrr m_exg
+
+ext NW M_DREG M_AM_NONE %0100100010000rrr m_reg +
+- L M_DREG M_AM_NONE %0100100011000rrr m_reg
+
+illegal N M_AM_NONE M_AM_NONE %0100101011111100 m_self
+
+jmp N C_CTRL M_AM_NONE %0100111011eee000 m_ea
+
+jsr N C_CTRL M_AM_NONE %0100111010eee000 m_ea
+
+lea NL C_CTRL M_AREG %0100rrr111eR1000 m_ea
+
+link N M_AREG M_IMMED %0100111001010rrr m_link
+
+lsl NBWL M_DREG M_DREG %1110rrr1ss101rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc1ss001rrr m_shi +
+- NBWL C_ALTMEM M_AM_NONE %1110001111eee000 m_ea +
+- NBWL M_DREG M_AM_NONE %11100011ss001rrS m_reg
+
+lsr NBWL M_DREG M_DREG %1110rrr0ss101rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc0ss001rrr m_shi +
+- NBWL C_ALTMEM M_AM_NONE %1110001011eee000 m_ea +
+- NBWL M_DREG M_AM_NONE %11100010ss001rrS m_reg
+
+move NBWL C_ALL C_ALTDATA %00ssddddddssssss m_move +
+- NWL C_ALL M_AREG %00ssddd001ssssss m_move +
+- NW C_DATA M_AM_SR %0100011011sss000 m_ea +
+- NW M_AM_SR C_ALTDATA %0100000011ddd001 m_ea +
+- NW C_DATA M_AM_CCR %0100010011sss000 m_ea +
+- NL M_AM_USP M_AREG %0100111001101rrr m_usp +
+- NL M_AREG M_AM_USP %0100111001100rrr m_usp
+
+movea NWL C_ALL M_AREG %00ssddd001ssssss m_move
+
+movem ! M_AM_NONE M_AM_NONE %01001d001seeeeee m_movem
+
+movep NWL M_DREG M_AIND|M_ADISP %0000rrr11s001aaa m_movep +
+- NWL M_AIND|M_ADISP M_DREG %0000rrr10s001aaa m_movep
+
+moveq NL M_IMMED M_DREG %0111rrr0dddddddd m_moveq
+
+muls NW C_DATA M_DREG %1100rrr111eR1000 m_ea
+mulu NW C_DATA M_DREG %1100rrr011eR1000 m_ea
+nbcd NB C_ALTDATA M_AM_NONE %0100100000eee000 m_ea
+neg NBWL C_ALTDATA M_AM_NONE %01000100sseeeS00 m_ea
+negx NBWL C_ALTDATA M_AM_NONE %01000000sseeeS00 m_ea
+nop N M_AM_NONE M_AM_NONE 0x4e71 m_self
+not NBWL C_ALTDATA M_AM_NONE %01000110sseee100 m_ea
+
+or NBWL C_DATA M_DREG %1000rrr0sseR1S00 m_ea +
+- NBWL M_DREG C_MEM %1000rrr1sseR0S01 m_ea +
+ori NBWL M_IMMED C_ALTDATA %00000000sseeeS11 m_ea +
+- NB M_IMMED M_AM_CCR %0000000000111100 m_imm8 +
+- NW M_IMMED M_AM_SR %0000000001111100 m_imm
+
+pea NL C_CTRL M_AM_NONE %0100100001eee000 m_ea
+
+reset N M_AM_NONE M_AM_NONE 0x4e70 m_self
+
+rol NBWL M_DREG M_DREG %1110rrr1ss111rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc1ss011rrr m_shi +
+- NBWL C_ALTMEM M_AM_NONE %1110011111eee000 m_ea +
+- NBWL M_DREG M_AM_NONE %11100011ss011rrS m_reg
+
+ror NBWL M_DREG M_DREG %1110rrr0ss111rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc0ss011rrr m_shi +
+- NBWL C_ALTMEM M_AM_NONE %1110011011eee000 m_ea +
+- NBWL M_DREG M_AM_NONE %11100010ss011rrS m_reg
+
+roxl NBWL M_DREG M_DREG %1110rrr1ss110rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc1ss010rrr m_shi +
+- NBWL C_ALTMEM M_AM_NONE %1110010111eee000 m_ea +
+- NBWL M_DREG M_AM_NONE %11100011ss010rrS m_reg
+
+roxr NBWL M_DREG M_DREG %1110rrr0ss110rrr m_shr +
+- NBWL M_IMMED M_DREG %1110ccc0ss010rrr m_shi +
+- NBWL C_ALTMEM M_AM_NONE %1110010011eee000 m_ea +
+- NBWL M_DREG M_AM_NONE %11100010ss010rrS m_reg
+
+rte N M_AM_NONE M_AM_NONE 0x4e73 m_self
+rtr N M_AM_NONE M_AM_NONE 0x4e77 m_self
+rts N M_AM_NONE M_AM_NONE 0x4e75 m_self
+
+sbcd NB M_DREG M_DREG %1000rrr100000rrr m_abcd +
+- NB M_APREDEC M_APREDEC %1000rrr100001rrr m_abcd
+
+scc NB C_ALTDATA M_AM_NONE %0101010011eee000 m_ea
+shs
+scs NB C_ALTDATA M_AM_NONE %0101010111eee000 m_ea
+slo
+seq NB C_ALTDATA M_AM_NONE %0101011111eee000 m_ea
+sze
+sf NB C_ALTDATA M_AM_NONE %0101000111eee000 m_ea
+sge NB C_ALTDATA M_AM_NONE %0101110011eee000 m_ea
+sgt NB C_ALTDATA M_AM_NONE %0101111011eee000 m_ea
+shi NB C_ALTDATA M_AM_NONE %0101001011eee000 m_ea
+sle NB C_ALTDATA M_AM_NONE %0101111111eee000 m_ea
+sls NB C_ALTDATA M_AM_NONE %0101001111eee000 m_ea
+slt NB C_ALTDATA M_AM_NONE %0101110111eee000 m_ea
+smi NB C_ALTDATA M_AM_NONE %0101101111eee000 m_ea
+sne NB C_ALTDATA M_AM_NONE %0101011011eee000 m_ea
+snz
+spl NB C_ALTDATA M_AM_NONE %0101101011eee000 m_ea
+st NB C_ALTDATA M_AM_NONE %0101000011eee000 m_ea
+svc NB C_ALTDATA M_AM_NONE %0101100011eee000 m_ea
+svs NB C_ALTDATA M_AM_NONE %0101100111eee000 m_ea
+
+stop N M_IMMED M_AM_NONE %0100111001110010 m_imm
+
+sub NBWL C_ALL M_DREG %1001rrr0sseR1S00 m_ea +
+- NBWL M_DREG C_ALTMEM %1001rrr1sseR0S01 m_ea +
+suba NWL C_ALL M_AREG %1001rrrs11eeeeee m_adda +
+subi NBWL M_IMMED C_ALTDATA %00000100sseeeS11 m_ea
+
+subq NBWL M_IMMED C_ALT %0101ddd1sseeeeee m_addq
+
+subx NBWL M_DREG M_DREG %1001xxx1ss000yyS m_abcd +
+- NBWL M_APREDEC M_APREDEC %1001xxx1ss001yyS m_abcd
+
+swap NW M_DREG M_AM_NONE %0100100001000rrr m_reg
+tas NB C_ALTDATA M_AM_NONE %0100101011eee000 m_ea
+trap N M_IMMED M_AM_NONE %010011100100vvvv m_trap
+trapv N M_AM_NONE M_AM_NONE 0x4e76 m_self
+tst NBWL C_ALTDATA M_AM_NONE %01001010sseeeS00 m_ea
+unlk N M_AREG M_AM_NONE %0100111001011rrr m_reg
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// AMODE.C - Addressing Modes
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "amode.h"
+#include "error.h"
+#include "token.h"
+#include "expr.h"
+#include "rmac.h"
+
+#define DEF_KW
+#include "kwtab.h"
+#define DEF_MN
+#include "mntab.h"
+
+// Address-mode information
+int nmodes; // Number of addr'ing modes found
+int am0; // Addressing mode
+int a0reg; // Register
+TOKEN a0expr[EXPRSIZE]; // Expression
+VALUE a0exval; // Expression's value
+WORD a0exattr; // Expression's attribute
+int a0ixreg; // Index register
+int a0ixsiz; // Index register size (and scale)
+TOKEN a0oexpr[EXPRSIZE]; // Outer displacement expression
+VALUE a0oexval; // Outer displacement value
+WORD a0oexattr; // Outer displacement attribute
+SYM *a0esym; // External symbol involved in expr
+
+int am1; // Addressing mode
+int a1reg; // Register
+TOKEN a1expr[EXPRSIZE]; // Expression
+VALUE a1exval; // Expression's value
+WORD a1exattr; // Expression's attribute
+int a1ixreg; // Index register
+int a1ixsiz; // Index register size (and scale)
+TOKEN a1oexpr[EXPRSIZE]; // Outer displacement expression
+VALUE a1oexval; // Outer displacement value
+WORD a1oexattr; // Outer displacement attribute
+SYM *a1esym; // External symbol involved in expr
+
+//
+// --- Parse Addressing Mode -----------------------------------------------------------------------
+//
+
+int amode(int acount) {
+ // Initialize global return values
+ nmodes = a0reg = a1reg = 0;
+ am0 = am1 = AM_NONE;
+ a0expr[0] = a0oexpr[0] = a1expr[0] = a1oexpr[0] = ENDEXPR;
+ a0exattr = a0oexattr = a1exattr = a1oexattr = 0;
+ a0esym = a1esym = (SYM *)NULL;
+
+ // If at EOL, then no addr modes at all
+ if(*tok == EOL)
+ return(0);
+
+ // Parse first addressing mode
+ #define AnOK a0ok
+ #define AMn am0
+ #define AnREG a0reg
+ #define AnIXREG a0ixreg
+ #define AnIXSIZ a0ixsiz
+ #define AnEXPR a0expr
+ #define AnEXVAL a0exval
+ #define AnEXATTR a0exattr
+ #define AnOEXPR a0oexpr
+ #define AnOEXVAL a0oexval
+ #define AnOEXATTR a0oexattr
+ #define AnESYM a0esym
+ #define AMn_IX0 am0_ix0
+ #define AMn_IXN am0_ixn
+ #include "parmode.h"
+
+ // If caller wants only one mode, return just one (ignore comma);
+ // If there is no second addressing mode (no comma), then return just one anyway.
+ nmodes = 1;
+ if(acount == 0 || *tok != ',')
+ return(1);
+ ++tok; // Eat comma
+
+ // Parse second addressing mode
+ #define AnOK a1ok
+ #define AMn am1
+ #define AnREG a1reg
+ #define AnIXREG a1ixreg
+ #define AnIXSIZ a1ixsiz
+ #define AnEXPR a1expr
+ #define AnEXVAL a1exval
+ #define AnEXATTR a1exattr
+ #define AnOEXPR a1oexpr
+ #define AnOEXVAL a1oexval
+ #define AnOEXATTR a1oexattr
+ #define AnESYM a1esym
+ #define AMn_IX0 am1_ix0
+ #define AMn_IXN am1_ixn
+ #include "parmode.h"
+
+ nmodes = 2;
+ return(2);
+
+ // Error messages:
+ badmode:
+
+ return(error("addressing mode syntax"));
+
+ unmode:
+
+ return(error("unimplemented addressing mode"));
+}
+
+//
+// --- Parse Register List -------------------------------------------------------------------------
+//
+
+int reglist(WORD *a_rmask) {
+ static WORD msktab[] = {
+ 0x0001, 0x0002, 0x0004, 0x0008,
+ 0x0010, 0x0020, 0x0040, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800,
+ 0x1000, 0x2000, 0x4000, 0x8000
+ };
+ WORD rmask;
+ int r, cnt;
+
+ rmask = 0;
+ for(;;) {
+ if(*tok >= KW_D0 && *tok <= KW_A7)
+ r = *tok++ & 15;
+ else break;
+
+ if(*tok == '-') {
+ ++tok;
+ if(*tok >= KW_D0 && *tok <= KW_A7)
+ cnt = *tok++ & 15;
+ else
+ return(error("register list syntax"));
+
+ if(cnt < r)
+ return(error("register list order"));
+ cnt -= r;
+ } else
+ cnt = 0;
+
+ while(cnt-- >= 0)
+ rmask |= msktab[r++];
+ if(*tok != '/')
+ break;
+ ++tok;
+ }
+
+ *a_rmask = rmask;
+
+ return(OK);
+}
+
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// AMODE.H - Addressing Modes
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __AMODE_H__
+#define __AMODE_H__
+
+#include "rmac.h"
+
+// 68000 and 68020 addressing modes
+#define DREG 000 // Dn
+#define AREG 010 // An
+#define AIND 020 // (An)
+#define APOSTINC 030 // (An)+
+#define APREDEC 040 // -(An)
+#define ADISP 050 // (d16,An) d16(An)
+#define AINDEXED 060 // (d8,An,Xn) d8(An,Xn)
+#define ABSW 070 // xxx.W
+#define ABSL 071 // xxx or xxx.L
+#define PCDISP 072 // (d16,PC) d16(PC)
+#define PCINDEXED 073 // (d16,PC,Xn) d16(PC,Xn)
+#define IMMED 074 // #data
+#define ABASE 0100 // (bd,An,Xn)
+#define MEMPOST 0101 // ([bd,An],Xn,od)
+#define MEMPRE 0102 // ([bc,An,Xn],od)
+#define PCBASE 0103 // (bd,PC,Xn)
+#define PCMPOST 0104 // ([bd,PC],Xn,od)
+#define PCMPRE 0105 // ([bc,PC,Xn],od)
+#define AM_USP 0106
+#define AM_SR 0107
+#define AM_CCR 0110
+#define AM_NONE 0111 // Nothing
+
+// Addressing-mode masks
+#define M_DREG 0x00000001L // Dn
+#define M_AREG 0x00000002L // An
+#define M_AIND 0x00000004L // (An)
+#define M_APOSTINC 0x00000008L // (An)+
+#define M_APREDEC 0x00000010L // -(An)
+#define M_ADISP 0x00000020L // (d16,An) d16(An)
+#define M_AINDEXED 0x00000040L // (d8,An,Xn) d8(An,Xn)
+#define M_ABSW 0x00000080L // xxx.W
+#define M_ABSL 0x00000100L // xxx or xxx.L
+#define M_PCDISP 0x00000200L // (d16,PC) d16(PC)
+#define M_PCINDEXED 0x00000400L // (d16,PC,Xn) d16(PC,Xn)
+#define M_IMMED 0x00000800L // #data
+#define M_ABASE 0x00001000L // (bd,An,Xn)
+#define M_MEMPOST 0x00002000L // ([bd,An],Xn,od)
+#define M_MEMPRE 0x00004000L // ([bc,An,Xn],od)
+#define M_PCBASE 0x00008000L // (bd,PC,Xn)
+#define M_PCMPOST 0x00010000L // ([bd,PC],Xn,od)
+#define M_PCMPRE 0x00020000L // ([bc,PC,Xn],od)
+#define M_AM_USP 0x00040000L // USP
+#define M_AM_SR 0x00080000L // SR
+#define M_AM_CCR 0x00100000L // CCR
+#define M_AM_NONE 0x00200000L // (nothing)
+
+// Addr mode categories
+#define C_ALL 0x00000fffL
+#define C_DATA 0x00000ffdL
+#define C_MEM 0x00000ffcL
+#define C_CTRL 0x000007e4L
+#define C_ALT 0x000001ffL
+
+#define C_ALTDATA (C_DATA&C_ALT)
+#define C_ALTMEM (C_MEM&C_ALT)
+#define C_ALTCTRL (C_CTRL&C_ALT)
+#define C_LABEL (M_ABSW|M_ABSL)
+#define C_NONE M_AM_NONE
+
+// Scales
+#define TIMES1 00000 // (empty or *1)
+#define TIMES2 01000 // *2
+#define TIMES4 02000 // *4
+#define TIMES8 03000 // *8
+
+#define EXPRSIZE 128 // Maximum #tokens in an expression
+
+// Addressing mode variables, output of amode()
+extern int nmodes;
+extern int am0, am1;
+extern int a0reg, a1reg;
+extern TOKEN a0expr[], a1expr[];
+extern VALUE a0exval, a1exval;
+extern WORD a0exattr, a1exattr;
+extern int a0ixreg, a1ixreg;
+extern int a0ixsiz, a1ixsiz;
+extern TOKEN a0oexpr[], a1oexpr[];
+extern VALUE a0oexval, a1oexval;
+extern WORD a0oexattr, a1oexattr;
+extern SYM *a0esym, *a1esym;
+
+// Mnemonic table structure
+#define MNTAB struct _mntab
+MNTAB {
+ WORD mnattr; // Attributes (CGSPECIAL, SIZN, ...)
+ LONG mn0, mn1; // Addressing modes
+ WORD mninst; // Instruction mask
+ WORD mncont; // Continuation (or -1)
+ int (*mnfunc)(); // Mnemonic builder
+};
+
+// mnattr:
+#define CGSPECIAL 0x8000 // Special (don't parse addr modes)
+
+// Prototypes
+int amode(int);
+int reglist(WORD *);
+
+#endif // __AMODE_H__
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// DEBUG.C - Debugging Messages
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "debug.h"
+#include "sect.h"
+#include "amode.h"
+#include "mark.h"
+
+static int siztab[4] = {3, 5, 9, 9};
+
+//
+// --- Print 'c' Visibly ---------------------------------------------------------------------------
+//
+
+int visprt(char c) {
+ if(c < 0x20 || c >= 0x7f)
+ putchar('.');
+ else
+ putchar(c);
+
+ return(0);
+}
+
+//
+// --- Print expression, return ptr to just past the ENDEXPR ---------------------------------------
+//
+
+TOKEN *printexpr(TOKEN *tp) {
+ if(tp != NULL)
+ while(*tp != ENDEXPR)
+ switch((int)*tp++) {
+ case SYMBOL:
+ printf("`%s' ", ((SYM *)*tp)->sname);
+ ++tp;
+ break;
+ case CONST:
+ printf("$%lx ", *tp++);
+ break;
+ case ACONST:
+ printf("ACONST=($%lx,$%lx) ", *tp, tp[1]);
+ tp += 2;
+ break;
+ default:
+ printf("%c ", (char)tp[-1]);
+ break;
+ }
+ printf(";\n");
+ return(tp + 1);
+}
+
+//
+// --- Dump data in a chunk (and maybe others) in the appropriate format ---------------------------
+//
+
+int chdump(CHUNK *ch, int format) {
+ while(ch != NULL) {
+ printf("chloc=$%08lx, chsize=$%lx\n", ch->chloc, ch->ch_size);
+ mdump(ch->chptr, ch->ch_size, format, ch->chloc);
+ ch = ch->chnext;
+ }
+
+ return(0);
+}
+
+//
+// --- Dump fixup records in printable format ------------------------------------------------------
+//
+
+int fudump(CHUNK *ch) {
+ PTR p;
+ char *ep;
+ WORD attr, esiz;
+ WORD line, file;
+ LONG loc;
+
+ for(; ch != NULL;) {
+ p.cp = ch->chptr;
+ ep = ch->chptr + ch->ch_size;
+ while(p.cp < ep) {
+ attr = *p.wp++;
+ loc = *p.lp++;
+ file = *p.wp++;
+ line = *p.wp++;
+
+ printf("$%04x $%08lx %d.%d: ", (int)attr, loc, (int)file, (int)line);
+
+ if(attr & FU_EXPR) {
+ esiz = *p.wp++;
+ printf("(%d long) ", (int)esiz);
+ p.tk = printexpr(p.tk);
+ } else {
+ printf("`%s' ;\n", (*p.sy)->sname);
+ ++p.lp;
+ }
+ }
+ ch = ch->chnext;
+ }
+
+ return(0);
+}
+
+//
+// --- Dump marks ----------------------------------------------------------------------------------
+//
+
+int mudump(void) {
+ MCHUNK *mch;
+ PTR p;
+ WORD from;
+ WORD w;
+ LONG loc;
+ SYM *symbol;
+
+ from = 0;
+ for(mch = firstmch; mch != NULL; mch = mch->mcnext) {
+ printf("mch=$%08lx mcptr=$%08lx mcalloc=$%lx mcused=$%x\n",
+ mch,
+ mch->mcptr,
+ mch->mcalloc,
+ mch->mcused);
+
+ p = mch->mcptr;
+ for(;;) {
+ w = *p.wp++;
+ if(w & MCHEND)
+ break;
+
+ symbol = NULL;
+ loc = *p.lp++;
+
+ if(w & MCHFROM)
+ from = *p.wp++;
+
+ if(w & MSYMBOL)
+ symbol = *p.sy++;
+
+ printf("m=$%04x to=%d loc=$%lx from=%d siz=%s",
+ w, w & 0x00ff, loc, from, (w & MLONG) ? "long" : "word");
+
+ if(symbol != NULL)
+ printf(" sym=`%s'", symbol->sname);
+ printf("\n");
+ }
+ }
+
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Dump memory from 'start' for 'count' bytes; `flg' is the following ORed together:
+// 0 - bytes
+// 1 - words
+// 2 - longwords
+//
+// if `base' is not -1, then print it at the start of each line, incremented accordingly.
+// -------------------------------------------------------------------------------------------------
+//
+
+int mdump(char *start, LONG count, int flg, LONG base) {
+ int i, j, k;
+
+ j = 0;
+ for(i = 0; i < (int)count;) {
+ if((i & 15) == 0) {
+ if(j < i) {
+ printf(" ");
+ while(j < i)
+ visprt(start[j++]);
+ putchar('\n');
+ }
+ j = i;
+ if(base != -1)
+ printf("%08lx ", base);
+ }
+
+ switch(flg & 3) {
+ case 0:
+ printf("%02x ", start[i] & 0xff);
+ ++i;
+ break;
+ case 1:
+ printf("%02x%02x ", start[i] & 0xff, start[i+1] & 0xff);
+ i += 2;
+ break;
+ case 2:
+ printf("%02x%02x%02x%02x ", start[i] & 0xff, start[i+1] & 0xff,
+ start[i+2] & 0xff, start[i+3] & 0xff);
+ i += 4;
+ break;
+ case 3:
+ break;
+ }
+
+ if(base != -1)
+ base += 1 << (flg & 3);
+ }
+
+ // Print remaining bit of ascii; the hairy expression computes the number of
+ // spaces to print to make the ascii line up nicely.
+ if(j != i) {
+ k = ((16 - (i - j)) / (1 << (flg & 3))) * siztab[flg & 3];
+ while(k--)
+ putchar(' ');
+ printf(" ");
+ while(j < i)
+ visprt(start[j++]);
+ putchar('\n');
+ }
+
+ return(0);
+}
+
+//
+// --- Dump list of tokens on stdout in printable form ---------------------------------------------
+//
+
+int dumptok(TOKEN *tk) {
+ int flg = 0;
+
+ while(*tk != EOL) {
+ if(flg++)
+ printf(" ");
+
+ if(*tk >= 128) {
+ printf("REG=%ld", *tk++ - 128);
+ continue;
+ }
+
+ switch((int)*tk++) {
+ case CONST: // CONST <value>
+ printf("CONST=%ld", *tk++);
+ break;
+ case STRING: // STRING <address>
+ printf("STRING='%s'", *tk++);
+ break;
+ case SYMBOL: // SYMBOL <address>
+ printf("SYMBOL='%s'", *tk++);
+ break;
+ case EOL: // End of line
+ printf("EOL");
+ break;
+ case TKEOF: // End of file (or macro)
+ printf("TKEOF");
+ break;
+ case DEQUALS: // ==
+ printf("DEQUALS");
+ break;
+ case DCOLON: // ::
+ printf("DCOLON");
+ break;
+ case GE: // >=
+ printf("GE");
+ break;
+ case LE: // <=
+ printf("LE");
+ break;
+ case NE: // <> or !=
+ printf("NE");
+ break;
+ case SHR: // >>
+ printf("SHR");
+ break;
+ case SHL: // <<
+ printf("SHL");
+ break;
+ default:
+ printf("%c", tk[-1]);
+ break;
+ }
+ }
+ printf("\n");
+
+ return(0);
+}
+
+//
+// --- Dump Everything -----------------------------------------------------------------------------
+//
+
+int dump_everything(void) {
+ int i;
+
+ for(i = 1; i < NSECTS; ++i)
+ if(sect[i].scattr & SUSED) {
+ printf("Section %d sloc=$%lx\n", i, sect[i].sloc);
+ printf("Code:\n");
+ chdump(sect[i].sfcode, 1);
+
+ printf("Fixup:\n");
+ fudump(sect[i].sffix);
+
+ printf("\n");
+ }
+
+ printf("\nMarks:\n");
+ mudump(); // Dump marks
+ printf("Total memory allocated=$%lx\n", amemtot);
+
+ return(0);
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// DEBUG.H - Debugging Messages
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#include "rmac.h"
+
+// Prototypes
+int mudump(void);
+int mdump(char *, LONG, int, LONG);
+int dumptok(TOKEN *);
+int dump_everything(void);
+
+#endif // __DEBUG_H__
\ No newline at end of file
--- /dev/null
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// DIRECT.C - Directive Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+//
+
+#include "direct.h"
+#include "sect.h"
+#include "risca.h"
+#include "error.h"
+#include "token.h"
+#include "procln.h"
+#include "expr.h"
+#include "mach.h"
+#include "listing.h"
+#include "mark.h"
+#include "symbol.h"
+
+#define DEF_KW
+#include "kwtab.h"
+
+TOKEN exprbuf[128]; // Expression buffer
+
+// Directive handler table
+int (*dirtab[])() = {
+ d_org, // 0 org
+ d_even, // 1 even
+ d_unimpl, // 2 .6502
+ d_68000, // 3 .68000
+ d_bss, // 4 bss
+ d_data, // 5 data
+ d_text, // 6 text
+ d_abs, // 7 abs
+ d_comm, // 8 comm
+ d_init, // 9 init
+ d_cargs, // 10 cargs
+ d_goto, // 11 goto
+ d_dc, // 12 dc
+ d_ds, // 13 ds
+ d_undmac, // 14 undefmac
+ d_gpu, // 15 .gpu
+ d_dsp, // 16 .dsp
+ d_dcb, // 17 dcb
+ d_unimpl, // 18* set
+ d_unimpl, // 19* reg
+ d_unimpl, // 20 dump
+ d_incbin, // 21 .incbin //load
+ d_unimpl, // 22 disable
+ d_unimpl, // 23 enable
+ d_globl, // 24 globl
+ d_regbank0, // 25 .regbank0
+ d_regbank1, // 26 .regbank1
+ d_unimpl, // 27 xdef
+ d_assert, // 28 assert
+ d_unimpl, // 29* if
+ d_unimpl, // 30* endif
+ d_unimpl, // 31* endc
+ d_unimpl, // 32* iif
+ d_include, // 33 include
+ fpop, // 34 end
+ d_unimpl, // 35* macro
+ exitmac, // 36* exitm
+ d_unimpl, // 37* endm
+ d_list, // 38 list
+ d_nlist, // 39 nlist
+ d_long, // 40* rept
+ d_phrase, // 41* endr
+ d_dphrase, // 42 struct
+ d_qphrase, // 43 ends
+ d_title, // 44 title
+ d_subttl, // 45 subttl
+ eject, // 46 eject
+ d_unimpl, // 47 error
+ d_unimpl, // 48 warn
+ d_noclear, // 49 .noclear
+ d_equrundef, // 50 .equrundef/.regundef
+ d_ccundef, // 51 .ccundef
+ d_print, // 52 .print
+ d_gpumain, // 53 .gpumain
+ d_jpad, // 54 .jpad
+ d_nojpad, // 55 .nojpad
+ d_fail, // 56 .fail
+};
+
+//
+// --- .org - Set origin ---------------------------------------------------------------------------
+//
+
+int d_fail(void) {
+ fatal("user abort");
+ return(0);
+}
+
+//
+// --- .org - Set origin ---------------------------------------------------------------------------
+//
+
+int d_org(void) {
+ VALUE address;
+
+ if(!rgpu && !rdsp)
+ return(error(".org permitted only in gpu/dsp section"));
+
+ orgaddr = 0;
+
+ if(abs_expr(&address) == ERROR) {
+ error("cannot determine org'd address");
+ return(ERROR);
+ }
+
+ orgaddr = address;
+ orgactive = 1;
+
+ return(0);
+}
+
+//
+// --- NOP Padding Directive -----------------------------------------------------------------------
+//
+
+int d_jpad(void) {
+ jpad = 1;
+ return(0);
+}
+
+int d_nojpad(void) {
+ jpad = 0;
+ return(0);
+}
+
+//
+// --- Print Directive -----------------------------------------------------------------------------
+//
+
+int d_print(void) {
+ char prntstr[LNSIZ]; // String for PRINT directive
+ char format[LNSIZ]; // Format for PRINT directive
+ int formatting = 0; // Formatting on/off
+ int wordlong = 0; // WORD = 0, LONG = 1
+ int outtype = 0; // 0:hex, 1:decimal, 2:unsigned
+
+ VALUE eval; // Expression value
+ WORD eattr; // Expression attributes
+ SYM *esym; // External symbol involved in expr.
+ TOKEN r_expr[EXPRSIZE];
+
+ while(*tok != EOL) {
+ switch(*tok) {
+ case STRING:
+ sprintf(prntstr, "%s", (char*)tok[1]);
+ printf("%s", prntstr);
+ if(list_fd)
+ write(list_fd, prntstr, (LONG)strlen(prntstr));
+ tok+=2;
+ break;
+ case '/':
+ formatting = 1;
+ if(tok[1] != SYMBOL) goto token_err;
+ strcpy(prntstr, (char*)tok[2]);
+ switch(prntstr[0]) {
+ case 'l': case 'L': wordlong = 1; break;
+ case 'w': case 'W': wordlong = 0; break;
+ case 'x': case 'X': outtype = 0; break;
+ case 'd': case 'D': outtype = 1; break;
+ case 'u': case 'U': outtype = 2; break;
+ default:
+ error("unknown print format flag");
+ return(ERROR);
+ }
+ tok += 3;
+ break;
+ case ',':
+ tok++;
+ break;
+ default:
+ if(expr(r_expr, &eval, &eattr, &esym) != OK)
+ goto token_err;
+ else {
+ switch(outtype) {
+ case 0: strcpy(format, "%X"); break;
+ case 1: strcpy(format, "%d" ); break;
+ case 2: strcpy(format, "%u" ); break;
+ }
+ if(wordlong) sprintf(prntstr, format, eval);
+ else sprintf(prntstr, format, eval & 0xFFFF);
+ printf("%s", prntstr);
+ if(list_fd)
+ write(list_fd, prntstr, (LONG)strlen(prntstr));
+ formatting = 0;
+ wordlong = 0;
+ outtype = 0;
+ }
+ break;
+ }
+ }
+
+ printf("\n");
+ println("\n");
+
+ return(0);
+
+ token_err:
+ error("illegal print token");
+ return(ERROR);
+}
+
+//
+// --- Undefine an Equated Condition Code ----------------------------------------------------------
+//
+
+int d_ccundef(void) {
+ SYM *ccname;
+
+ if(!rgpu && !rdsp) { // Check that we are in a RISC section
+ error(".ccundef must be defined in .gpu/.dsp section");
+ return(ERROR);
+ }
+ if(*tok != SYMBOL) {
+ error(syntax_error);
+ return(ERROR);
+ }
+ ccname = lookup((char *)tok[1], LABEL, 0);
+ if(!ccname || !(ccname->sattre & EQUATEDCC)) { // Make sure symbol is a valid ccdef
+ error("invalid equated condition name specified");
+ return(ERROR);
+ }
+
+ ccname->sattre |= UNDEF_CC;
+
+ return(0);
+}
+
+//
+// --- Undefine an Equated Register ----------------------------------------------------------------
+//
+
+int d_equrundef(void) {
+ SYM *regname;
+
+ if(!rgpu && !rdsp) { // Check that we are in a RISC section
+ error(".equrundef/.regundef must be defined in .gpu/.dsp section");
+ return(ERROR);
+ }
+
+ while(*tok != EOL) {
+ if(*tok == ',') tok++; // Skip preceeding or seperating commas
+
+ if(*tok != SYMBOL) { // Check we are dealing with a symbol
+ error(syntax_error);
+ return(ERROR);
+ }
+
+ regname = lookup((char *)tok[1], LABEL, 0); // Lookup and undef if equated register
+ if(regname && (regname->sattre & EQUATEDREG))
+ regname->sattre |= UNDEF_EQUR;
+
+ tok += 2; // Skip over symbol token and address
+ }
+
+ return(0);
+}
+
+//
+// --- Do Not Allow the Use of the CLR.L Opcode ----------------------------------------------------
+//
+
+int d_noclear(void) {
+ return(0);
+}
+
+//
+// --- Include Binary File -------------------------------------------------------------------------
+//
+
+int d_incbin(void) {
+ int i, j;
+ int bytes = 0;
+ long pos, size;
+ char buf;
+
+ if(*tok != STRING) {
+ error(syntax_error);
+ return(ERROR);
+ }
+
+ if((j = open((char *)tok[1], _OPEN_INC)) >= 0) {
+ size = lseek(j, 0L, SEEK_END);
+ chcheck(size);
+ pos = lseek(j, 0L, SEEK_SET);
+
+ for(i = 0; i < size; i++) {
+ buf = '\0';
+ bytes = read(j, &buf, 1);
+ D_byte(buf);
+ }
+
+ } else {
+ errors("cannot open include binary file (%s)", (char*)tok[1]);
+ return(ERROR);
+ }
+
+ close(j);
+ return(0);
+}
+
+//
+// --- Set RISC Register Banks ---------------------------------------------------------------------
+//
+
+int d_regbank0(void) {
+ regbank = BANK_0; // Set active register bank zero
+ return(0);
+}
+
+int d_regbank1(void) {
+ regbank = BANK_1; // Set active register bank one
+ return(0);
+}
+
+//
+// --- Adjust Location to an EVEN Value ------------------------------------------------------------
+//
+
+int d_even(void) {
+ if(sloc & 1) {
+ if((scattr & SBSS) == 0) {
+ chcheck(1);
+ D_byte(0);
+ } else {
+ ++sloc;
+ }
+ }
+
+ return(0);
+}
+
+//
+// --- Adjust Location to an LONG Value ------------------------------------------------------------
+//
+
+int d_long(void) {
+ unsigned i;
+ unsigned val = 4;
+
+ i = sloc & ~(val - 1);
+ if(i != sloc) val = val - (sloc - i);
+ else val = 0;
+
+ if(val) {
+ if((scattr & SBSS) == 0) {
+ chcheck(val);
+ for(i = 0; i < val; i++)
+ D_byte(0);
+ } else {
+ sloc += val;
+ }
+ }
+
+ return(0);
+}
+
+//
+// --- Adjust Location to an PHRASE Value ----------------------------------------------------------
+//
+
+int d_phrase(void) {
+ unsigned i;
+ unsigned val = 8;
+
+ i = sloc & ~(val - 1);
+ if(i != sloc) val = val - (sloc - i);
+ else val = 0;
+
+ if(val) {
+ if((scattr & SBSS) == 0) {
+ chcheck(val);
+ for(i = 0; i < val; i++)
+ D_byte(0);
+ } else {
+ sloc += val;
+ }
+ }
+
+ return(0);
+}
+
+//
+// --- Adjust Location to an DPHRASE Value ---------------------------------------------------------
+//
+
+int d_dphrase(void) {
+ unsigned i;
+ unsigned val = 16;
+
+ i = sloc & ~(val - 1);
+ if(i != sloc) val = val - (sloc - i);
+ else val = 0;
+
+ if(val) {
+ if((scattr & SBSS) == 0) {
+ chcheck(val);
+ for(i = 0; i < val; i++)
+ D_byte(0);
+ } else {
+ sloc += val;
+ }
+ }
+
+ return(0);
+}
+
+//
+// --- Adjust Location to an QPHRASE Value ---------------------------------------------------------
+//
+
+int d_qphrase(void) {
+ unsigned i;
+ unsigned val = 32;
+
+ i = sloc & ~(val - 1);
+ if(i != sloc) val = val - (sloc - i);
+ else val = 0;
+
+ if(val) {
+ if((scattr & SBSS) == 0) {
+ savsect();
+ chcheck(val);
+ for(i = 0; i < val; i++)
+ D_byte(0);
+ } else {
+ sloc += val;
+ }
+ }
+
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Do auto-even. This must be called ONLY if 'sloc' is odd.
+//
+// This is made hairy because, if there was a label on the line, we also have to adjust its value.
+// This won't work with more than one label on the line, which is OK since multiple labels are only
+// allowed in AS68 kludge mode, and the C compiler is VERY paranoid and uses ".even" whenever it can
+// -------------------------------------------------------------------------------------------------
+//
+
+void auto_even(void) {
+ if(scattr & SBSS)
+ ++sloc; // Bump BSS section
+ else {
+ D_byte(0) // Deposit 0.b in non-BSS
+ }
+
+ if(lab_sym != NULL) // Bump label if we have to
+ ++lab_sym->svalue;
+}
+
+//
+// --- Unimplemened Directive Error ----------------------------------------------------------------
+//
+
+int d_unimpl(void) {
+ return(error("unimplemented directive"));
+}
+
+//
+// --- Return absolute (not TDB) and defined expression or return an error -------------------------
+//
+
+int abs_expr(VALUE *a_eval) {
+ WORD eattr;
+
+ if(expr(exprbuf, a_eval, &eattr, NULL) < 0)
+ return(ERROR);
+ if(!(eattr & DEFINED))
+ return(error(undef_error));
+ if(eattr & TDB)
+ return(error(rel_error));
+
+ return(OK);
+}
+
+//
+// --- Hand symbols in a symbol-list to a function (kind of like mapcar...) ------------------------
+//
+
+int symlist(int(*func)()) {
+ char *em = "symbol list syntax";
+
+ for(;;) {
+ if(*tok != SYMBOL) return(error(em));
+ if((*func)(tok[1]) != OK) break;
+ tok += 2;
+ if(*tok == EOL) break;
+ if(*tok != ',') return(error(em));
+ ++tok;
+ }
+
+ return(0);
+}
+
+//
+// --- .include "filename" -------------------------------------------------------------------------
+//
+
+int d_include(void) {
+ int j;
+ int i;
+ char *fn;
+ char buf[128];
+ char buf1[128];
+
+ if(*tok == STRING) // Leave strings ALONE
+ fn = (char *)*++tok;
+ else if(*tok == SYMBOL) { // Try to append ".s" to symbols
+ strcpy(buf, (char *)*++tok);
+ fext(buf, ".s", 0);
+ fn = &buf[0];
+ } else // Punt if no STRING or SYMBOL
+ return(error("missing filename"));
+
+ // Make sure the user didn't try anything like:
+ // .include equates.s
+ if(*++tok != EOL) return(error("extra stuff after filename -- enclose it in quotes"));
+
+ // Attempt to open the include file in the current directory, then (if that failed) try list
+ // of include files passed in the enviroment string or by the "-d" option.
+ if((j = open(fn, 0)) < 0) {
+ for(i = 0; nthpath("RMACPATH", i, buf1) != 0; ++i) {
+ j = strlen(buf1);
+ if(j > 0 && buf1[j-1] != SLASHCHAR) // Append path char if necessary
+ strcat(buf1, SLASHSTRING);
+ strcat(buf1, fn);
+ if((j = open(buf1, 0)) >= 0)
+ goto allright;
+ }
+
+ return(errors("cannot open: \"%s\"", fn));
+ }
+
+ allright:
+
+ include(j, fn);
+ return(0);
+}
+
+//
+// --- .assert expression [, expression...] --------------------------------------------------------
+//
+
+int d_assert(void) {
+ WORD eattr;
+ VALUE eval;
+
+ for(; expr(exprbuf, &eval, &eattr, NULL) == OK; ++tok) {
+ if(!(eattr & DEFINED))
+ return(error("forward or undefined .assert"));
+ if(!eval)
+ return(error("assert failure"));
+ if(*tok != ',')
+ break;
+ }
+ at_eol();
+ return(0);
+}
+
+//
+// --- .globl symbol [, symbol] <<<cannot make local symbols global>>> -----------------------------
+//
+
+int globl1(char *p) {
+ SYM *sy;
+
+ if(*p == '.')
+ return(error("cannot .globl local symbol"));
+ if((sy = lookup(p, LABEL, 0)) == NULL) {
+ sy = newsym(p, LABEL, 0);
+ sy->svalue = 0;
+ sy->sattr = GLOBAL;
+ } else
+ sy->sattr |= GLOBAL;
+
+ return(OK);
+}
+
+int d_globl(void) {
+ symlist(globl1);
+ return(0);
+}
+
+//
+// --- .abs [expression] ---------------------------------------------------------------------------
+//
+
+int d_abs(void) {
+ VALUE eval;
+
+ savsect();
+ if(*tok == EOL)
+ eval = 0;
+ else
+ if(abs_expr(&eval) != OK)
+ return(0);
+
+ switchsect(ABS);
+ sloc = eval;
+ return(0);
+}
+
+//
+// --- Switch Segments -----------------------------------------------------------------------------
+//
+
+int d_text(void) {
+ if(rgpu || rdsp)
+ return(error("directive forbidden in gpu/dsp mode"));
+
+ if(cursect != TEXT) {
+ savsect();
+ switchsect(TEXT);
+ }
+ return(0);
+}
+
+int d_data(void) {
+ if(rgpu || rdsp)
+ return(error("directive forbidden in gpu/dsp mode"));
+
+ if(cursect != DATA) {
+ savsect();
+ switchsect(DATA);
+ }
+ return(0);
+}
+
+int d_bss(void) {
+ if(rgpu || rdsp)
+ return(error("directive forbidden in gpu/dsp mode"));
+
+ if(cursect != BSS) {
+ savsect();
+ switchsect(BSS);
+ }
+ return(0);
+}
+
+//
+// --- .ds[.size] expression -----------------------------------------------------------------------
+//
+
+int d_ds(WORD siz) {
+ VALUE eval;
+
+ // This gets kind of stupid. This directive is disallowed in normal 68000 mode ("for your own
+ // good!"), but is permitted for 6502 and Alcyon-compatibility modes.
+ // For obvious reasons, no auto-even is done in 8-bit processor modes.
+ if(as68_flag == 0 && (scattr & SBSS) == 0)
+ return(error(".ds permitted only in BSS"));
+
+ if(siz != SIZB && (sloc & 1)) // Automatic .even
+ auto_even();
+
+ if(abs_expr(&eval) != OK) return(0);
+
+ // In non-TDB section (BSS, ABS and M6502) just advance the location counter appropriately.
+ // In TDB sections, deposit (possibly large) chunks of zeroed memory....
+ if((scattr & SBSS)) {
+ listvalue(eval);
+ eval *= siz;
+ sloc += eval;
+ just_bss = 1; // No data deposited (8-bit CPU mode)
+ } else {
+ dep_block(eval, siz, (VALUE)0, (WORD)(DEFINED|ABS), NULL);
+ }
+
+ at_eol();
+ return(0);
+}
+
+//
+// --- dc.b, dc.w / dc, dc.l -----------------------------------------------------------------------
+//
+
+int d_dc(WORD siz) {
+ WORD eattr;
+ VALUE eval;
+ WORD tdb;
+ WORD defined;
+ LONG i;
+ char *p;
+ int movei = 0; // movei flag for dc.i
+
+ if((scattr & SBSS) != 0)
+ return(error("illegal initialization of section"));
+
+ if((siz != SIZB) && (sloc & 1))
+ auto_even();
+
+ for(;; ++tok) {
+ // dc.b 'string' [,] ...
+ if (siz == SIZB && *tok == STRING && (tok[2] == ',' || tok[2] == EOL)) {
+ i = strlen((const char*)tok[1]);
+ if((challoc - ch_size) < i)
+ chcheck(i);
+ for(p = (char *)tok[1]; *p != EOS; ++p)
+ D_byte(*p);
+ tok += 2;
+ goto comma;
+ }
+
+ if(*tok == 'I') {
+ movei = 1;
+ tok++;
+ siz = SIZL;
+ }
+
+ // dc.x <expression>
+ if(expr(exprbuf, &eval, &eattr, NULL) != OK)
+ return(0);
+ tdb = (WORD)(eattr & TDB);
+ defined = (WORD)(eattr & DEFINED);
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+
+ switch(siz) {
+ case SIZB:
+ if(!defined) {
+ fixup(FU_BYTE|FU_SEXT, sloc, exprbuf);
+ D_byte(0);
+ } else {
+ if(tdb)
+ return(error("non-absolute byte value"));
+ if(eval + 0x100 >= 0x200)
+ return(error(range_error));
+ D_byte(eval);
+ }
+ break;
+ case SIZW:
+ case SIZN:
+ if(!defined) {
+ fixup(FU_WORD|FU_SEXT, sloc, exprbuf);
+ D_word(0);
+ } else {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MWORD, NULL);
+ if(eval + 0x10000 >= 0x20000)
+ return(error(range_error));
+ // Deposit 68000 or 6502 (byte-reversed) word
+ D_word(eval);
+ }
+ break;
+ case SIZL:
+ if(!defined) {
+ if(movei)
+ fixup(FU_LONG|FU_MOVEI, sloc, exprbuf);
+ else
+ fixup(FU_LONG, sloc, exprbuf);
+ D_long(0);
+ } else {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MLONG, NULL);
+ if(movei)
+ eval = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
+ D_long(eval);
+ }
+ break;
+ }
+
+ comma:
+
+ if(*tok != ',')
+ break;
+ }
+
+ at_eol();
+ return(0);
+}
+
+//
+// --- dcb[.siz] expr1,expr2 - Make 'expr1' copies of 'expr2' --------------------------------------
+//
+
+int d_dcb(WORD siz) {
+ VALUE evalc, eval;
+ WORD eattr;
+
+ if((scattr & SBSS) != 0)
+ return(error("illegal initialization of section"));
+
+ if(abs_expr(&evalc) != OK)
+ return(0);
+
+ if(*tok++ != ',')
+ return(error("missing comma"));
+
+ if(expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return(0);
+
+ if((siz != SIZB) && (sloc & 1))
+ auto_even();
+
+ dep_block(evalc, siz, eval, eattr, exprbuf);
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Generalized initialization directive
+//
+// .init[.siz] [#count,] expression [.size] , ...
+//
+// The size suffix on the ".init" directive becomes the default size of the objects to deposit.
+// If an item is preceeded with a sharp (immediate) sign and an expression, it specifies a repeat
+// count. The value to be deposited may be followed by a size suffix, which overrides the
+// default size.
+// -------------------------------------------------------------------------------------------------
+//
+
+int d_init(WORD def_siz) {
+ VALUE count;
+ VALUE eval;
+ WORD eattr;
+ WORD siz;
+
+ if((scattr & SBSS) != 0)
+ return(error(".init not permitted in BSS or ABS"));
+
+ if(rgpu || rdsp)
+ return(error("directive forbidden in gpu/dsp mode"));
+
+ for(;;) {
+ // Get repeat count (defaults to 1)
+ if(*tok == '#') {
+ ++tok;
+ if(abs_expr(&count) != OK)
+ return(0);
+ if(*tok++ != ',')
+ return(error(comma_error));
+ } else
+ count = 1;
+
+ // Evaluate expression to deposit
+ if(expr(exprbuf, &eval, &eattr, NULL) < 0)
+ return(0);
+
+ switch((int)*tok++) { // Determine size of object to deposit
+ case DOTB: siz = SIZB; break;
+ case DOTW: siz = SIZB; break;
+ case DOTL: siz = SIZL; break;
+ default:
+ siz = def_siz;
+ --tok;
+ break;
+ }
+
+ dep_block(count, siz, eval, eattr, exprbuf);
+
+ switch((int)*tok) {
+ case EOL:
+ return(0);
+ case ',':
+ ++tok;
+ continue;
+ default:
+ return(error(comma_error));
+ }
+ }
+}
+
+//
+// --- Deposit 'count' values of size 'siz' in the current (non-BSS) segment -----------------------
+//
+
+int dep_block(VALUE count, WORD siz, VALUE eval, WORD eattr, TOKEN *exprbuf) {
+ WORD tdb;
+ WORD defined;
+
+ tdb = (WORD)(eattr & TDB);
+ defined = (WORD)(eattr & DEFINED);
+
+ while(count--) {
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+
+ switch(siz) {
+ case SIZB:
+ if(!defined) {
+ fixup(FU_BYTE|FU_SEXT, sloc, exprbuf);
+ D_byte(0);
+ } else {
+ if(tdb)
+ return(error("non-absolute byte value"));
+ if(eval + 0x100 >= 0x200)
+ return(error(range_error));
+ D_byte(eval);
+ }
+ break;
+ case SIZW:
+ case SIZN:
+ if(!defined) {
+ fixup(FU_WORD|FU_SEXT, sloc, exprbuf);
+ D_word(0);
+ } else {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MWORD, NULL);
+ if(eval + 0x10000 >= 0x20000)
+ return(error(range_error));
+
+ // Deposit 68000 or 6502 (byte-reversed) word
+ D_word(eval);
+ }
+ break;
+ case SIZL:
+ if(!defined) {
+ fixup(FU_LONG, sloc, exprbuf);
+ D_long(0);
+ } else {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MLONG, NULL);
+ D_long(eval);
+ }
+ break;
+ }
+ }
+ return(0);
+}
+
+//
+// --- .comm symbol, size --------------------------------------------------------------------------
+//
+
+int d_comm(void) {
+ SYM *sym;
+ char *p;
+ VALUE eval;
+
+ if(*tok != SYMBOL)
+ return(error("missing symbol"));
+ p = (char *)tok[1];
+ tok += 2;
+
+ if(*p == '.') // Cannot .comm a local symbol
+ return(error(locgl_error));
+
+ if((sym = lookup(p, LABEL, 0)) == NULL)
+ sym = newsym(p, LABEL, 0);
+ else {
+ if(sym->sattr & DEFINED)
+ return(error(".comm symbol already defined"));
+ }
+
+ sym->sattr = GLOBAL|COMMON|BSS;
+ if(*tok++ != ',')
+ return(error(comma_error));
+
+ if(abs_expr(&eval) != OK) // Parse size of common region
+ return(0);
+ sym->svalue = eval; // Install common symbol's size
+ at_eol();
+ return(0);
+}
+
+//
+// --- .list - Turn listing on --------------------------------------------------------------------
+//
+
+int d_list(void) {
+ if(list_flag)
+ ++listing;
+ return(0);
+}
+
+//
+// --- .nlist - Turn listing off -------------------------------------------------------------------
+//
+
+int d_nlist(void) {
+ if(list_flag)
+ --listing;
+ return(0);
+}
+
+//
+// --- .68000 - Back to 68000 TEXT segment ---------------------------------------------------------
+//
+
+int d_68000(void) {
+ rgpu = rdsp = 0;
+ in_main = 0;
+ // Switching from gpu/dsp sections should reset any ORG'd Address
+ orgactive = 0;
+ orgwarning = 0;
+ savsect();
+ switchsect(TEXT);
+ return(0);
+}
+
+//
+// --- .gpu - Switch to GPU Assembler --------------------------------------------------------------
+//
+
+int d_gpu(void) {
+ if((cursect != TEXT) && (cursect != DATA)) {
+ error(".gpu can only be used in the TEXT or DATA segments");
+ return(ERROR);
+ }
+ // If previous section was dsp or 68000 then we need to reset ORG'd Addresses
+ if(!rgpu) {
+ orgactive = 0;
+ orgwarning = 0;
+ }
+ rgpu = 1; // Set GPU assembly
+ rdsp = 0; // Unset DSP assembly
+ regbank = BANK_N; // Set no default register bank
+ in_main = 0;
+ jpad = 0;
+ return(0);
+}
+
+//
+// --- GPU Main Code Directive ---------------------------------------------------------------------
+//
+
+int d_gpumain(void) {
+ if((cursect != TEXT) && (cursect != DATA)) {
+ error(".gpumain can only be used in the TEXT or DATA segments");
+ return(ERROR);
+ }
+ // If previous section was dsp or 68000 then we need to reset ORG'd Addresses
+ if(!rgpu) {
+ orgactive = 0;
+ orgwarning = 0;
+ }
+ rgpu = 1; // Set GPU assembly
+ rdsp = 0; // Unset DSP assembly
+ regbank = BANK_N; // Set no default register bank
+ in_main = 1; // Enable main code execution rules
+ jpad = 0;
+ return(0);
+}
+
+//
+// --- .dsp - Switch to DSP Assembler --------------------------------------------------------------
+//
+
+int d_dsp(void) {
+ if((cursect != TEXT) && (cursect != DATA)) {
+ error(".dsp can only be used in the TEXT or DATA segments");
+ return(ERROR);
+ }
+ // If previous section was gpu or 68000 then we need to reset ORG'd Addresses
+ if(!rdsp) {
+ orgactive = 0;
+ orgwarning = 0;
+ }
+ rdsp = 1; // Set DSP assembly
+ rgpu = 0; // Unset GPU assembly
+ regbank = BANK_N; // Set no default register bank
+ in_main = 0;
+ jpad = 0;
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// .cargs [#offset], symbol[.size], ...
+//
+// Lists of registers may also be mentioned; they just take up space. Good for "documentation"
+// purposes.
+//
+// .cargs a6,.arg1, .arg2, .arg3...
+//
+// The symbols are ABS and EQUATED.
+// -------------------------------------------------------------------------------------------------
+//
+
+int d_cargs(void) {
+ VALUE eval;
+ WORD rlist;
+ SYM *sy;
+ char *p;
+ int env;
+ int i;
+
+ if(rgpu || rdsp)
+ return(error("directive forbidden in gpu/dsp mode"));
+
+ if(*tok == '#') {
+ ++tok;
+ if(abs_expr(&eval) != OK)
+ return(0);
+ if(*tok == ',') // Eat comma if it's there
+ ++tok;
+ } else
+ eval = 4;
+
+ for(;;) {
+ if(*tok == SYMBOL) {
+ p = (char *)tok[1];
+ if(*p == '.')
+ env = curenv;
+ else
+ env = 0;
+
+ sy = lookup(p, LABEL, env);
+ if(sy == NULL) {
+ sy = newsym(p, LABEL, env);
+ sy->sattr = 0;
+ } else
+ if(sy->sattr & DEFINED)
+ return(errors("multiply-defined label '%s'", p));
+
+ // Put symbol in "order of definition" list
+ if(!(sy->sattr & SDECLLIST)) sym_decl(sy);
+
+ sy->sattr |= ABS|DEFINED|EQUATED;
+ sy->svalue = eval;
+ tok += 2;
+
+ switch((int)*tok) {
+ case DOTL:
+ eval += 2;
+ case DOTB:
+ case DOTW:
+ ++tok;
+ }
+ eval += 2;
+ } else
+ if(*tok >= KW_D0 && *tok <= KW_A7) {
+ if(reglist(&rlist) < 0)
+ return(0);
+ for(i = 0; i++ < 16; rlist >>= 1)
+ if(rlist & 1)
+ eval += 4;
+ } else
+ switch((int)*tok) {
+ case KW_USP:
+ case KW_SSP:
+ case KW_PC:
+ eval += 2;
+ // FALLTHROUGH
+ case KW_SR:
+ case KW_CCR:
+ eval += 2;
+ ++tok;
+ break;
+ case EOL:
+ return(0);
+ default:
+ return(error(".cargs syntax"));
+ }
+
+ if(*tok == ',')
+ ++tok;
+ }
+}
+
+//
+// --- Undefine a macro - .undefmac macname [, macname...] -----------------------------------------
+//
+
+int undmac1(char *p) {
+ SYM *sy;
+
+ // If the macro symbol exists, cause it to dissappear
+ if((sy = lookup(p, MACRO, 0)) != NULL) sy->stype = (BYTE)SY_UNDEF;
+ return(OK);
+}
+
+int d_undmac(void) {
+ symlist(undmac1);
+ return(0);
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// DIRECT.H - Directive Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __DIRECT_H__
+#define __DIRECT_H__
+
+#include "rmac.h"
+
+// Globals, Externals etc
+extern TOKEN exprbuf[];
+extern int (*dirtab[])();
+
+// Prototypes
+int d_even(void);
+void auto_even(void);
+int dep_block(VALUE, WORD, VALUE, WORD, TOKEN *);
+int d_unimpl(void);
+int d_even(void);
+int d_6502(void);
+int d_68000(void);
+int d_bss(void);
+int d_data(void);
+int d_text(void);
+int d_abs(void);
+int d_comm(void);
+int d_dc(WORD);
+int d_ds(WORD);
+int d_dcb(WORD);
+int d_globl(void);
+int d_gpu(void);
+int d_dsp(void);
+int d_assert(void);
+int d_if(void);
+int d_endif(void);
+int d_include(void);
+int exitmac(void);
+int d_list(void);
+int d_nlist(void);
+int d_title(void);
+int d_subttl(void);
+int eject(void);
+int d_error(char *);
+int d_warn(char *);
+int d_org(void);
+int d_init(WORD);
+int d_cargs(void);
+int d_undmac(void);
+int d_regbank0(void);
+int d_regbank1(void);
+int d_long(void);
+int d_phrase(void);
+int d_dphrase(void);
+int d_qphrase(void);
+int d_incbin(void);
+int d_noclear(void);
+int d_equrundef(void);
+int d_ccundef(void);
+int d_print(void);
+int d_gpumain(void);
+int d_jpad(void);
+int d_nojpad(void);
+int d_fail(void);
+int symlist(int(*)());
+int abs_expr(VALUE *);
+
+#endif // __DIRECT_H__
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// EAGEN.C - Effective Address Code Generation
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "rmac.h"
+#include "amode.h"
+#include "sect.h"
+#include "mark.h"
+#include "error.h"
+#include "mach.h"
+#include "risca.h"
+
+#define eaNgen ea0gen
+#define amN am0
+#define aNexattr a0exattr
+#define aNexval a0exval
+#define aNexpr a0expr
+#define aNixreg a0ixreg
+#define aNixsiz a0ixsiz
+#include "eagen0.c"
+
+#define eaNgen ea1gen
+#define amN am1
+#define aNexattr a1exattr
+#define aNexval a1exval
+#define aNexpr a1expr
+#define aNixreg a1ixreg
+#define aNixsiz a1ixsiz
+#include "eagen0.c"
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// EAGEN0.C - Effective Address Code Generation
+// Generated Code for eaN (Included twice by "eagen.c")
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+int eaNgen(WORD siz) {
+ WORD w;
+ VALUE v;
+ WORD tdb;
+
+ v = aNexval;
+ w = (WORD)(aNexattr & DEFINED);
+ tdb = (WORD)(aNexattr & TDB);
+
+ switch(amN) {
+ case DREG: // "Do nothing" - they're in the opword
+ case AREG:
+ case AIND:
+ case APOSTINC:
+ case APREDEC:
+ case AM_USP:
+ case AM_CCR:
+ case AM_SR:
+ case AM_NONE:
+ break; // This is a performance hit, though
+ case ADISP: // expr(An)
+ if(w) { // Just deposit it
+ if(tdb)
+ rmark(cursect, sloc, tdb, MWORD, NULL);
+ if(v + 0x8000 >= 0x18000)
+ return(error(range_error));
+ D_word(v);
+ } else { // Arrange for fixup later on
+ fixup(FU_WORD|FU_SEXT, sloc, aNexpr);
+ D_word(0);
+ }
+ break;
+ case PCDISP:
+ if(w) { // Just deposit it
+ if((aNexattr & TDB) == cursect)
+ v -= (VALUE)sloc;
+ else if((aNexattr & TDB) != ABS)
+ error(rel_error);
+
+ if(v + 0x8000 >= 0x10000)
+ return(error(range_error));
+ D_word(v);
+ } else { // Arrange for fixup later on
+ fixup(FU_WORD|FU_SEXT|FU_PCREL, sloc, aNexpr);
+ D_word(0);
+ }
+ break;
+ case AINDEXED:
+ w = (WORD)((aNixreg << 12) | aNixsiz); // Compute ixreg and size+scale
+ if(aNexattr & DEFINED) { // Deposit a byte...
+ if(tdb)
+ return(error(abs_error)); // Can't mark bytes
+ if(v + 0x80 >= 0x180)
+ return(error(range_error));
+ w |= v & 0xff;
+ D_word(w);
+ } else { // Fixup the byte later
+ fixup(FU_BYTE|FU_SEXT, sloc+1, aNexpr);
+ D_word(w);
+ }
+ break;
+ case PCINDEXED:
+ w = (WORD)((aNixreg << 12) | aNixsiz); // Compute ixreg and size+scale
+ if(aNexattr & DEFINED) { // Deposit a byte...
+ if((aNexattr & TDB) == cursect)
+ v -= (VALUE)sloc;
+ else if((aNexattr & TDB) != ABS)
+ error(rel_error);
+
+ if(v + 0x80 >= 0x100)
+ return(error(range_error));
+ w |= v & 0xff;
+ D_word(w);
+ } else { // Fixup the byte later
+ fixup(FU_WBYTE|FU_SEXT|FU_PCREL, sloc, aNexpr);
+ D_word(w);
+ }
+ break;
+ case IMMED:
+ switch(siz) {
+ case SIZB:
+ if(w) {
+ if(tdb)
+ return(error("illegal byte-sized relative reference"));
+ if(v + 0x100 >= 0x200)
+ return(error(range_error));
+ D_word(v);
+ } else {
+ fixup(FU_BYTE|FU_SEXT, sloc+1, aNexpr);
+ D_word(0);
+ }
+ break;
+ case SIZW:
+ case SIZN:
+ if(w) {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MWORD, NULL);
+ if(v + 0x10000 >= 0x20000)
+ return(error(range_error));
+ D_word(v);
+ } else {
+ fixup(FU_WORD|FU_SEXT, sloc, aNexpr);
+ D_word(0);
+ }
+ break;
+ case SIZL:
+ if(w) {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MLONG, NULL);
+ D_long(v);
+ } else {
+ fixup(FU_LONG, sloc, aNexpr);
+ D_long(0);
+ }
+ break;
+ default:
+ interror(1); // IMMED size problem
+ }
+ break;
+ case ABSW:
+ if(w) {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MWORD, NULL);
+ if(v + 0x8000 >= 0x10000)
+ return(error(range_error));
+ D_word(v);
+ } else {
+ fixup(FU_WORD|FU_SEXT, sloc, aNexpr);
+ D_word(0);
+ }
+ break;
+ case ABSL:
+ if(w) {
+ if(tdb)
+ rmark(cursect, sloc, tdb, MLONG, NULL);
+ D_long(v);
+ } else {
+ fixup(FU_LONG, sloc, aNexpr);
+ D_long(0);
+ }
+ break;
+ case ABASE:
+ case MEMPOST:
+ case MEMPRE:
+ case PCBASE:
+ case PCMPOST:
+ case PCMPRE:
+ return(error("unsupported 68020 addressing mode"));
+ default:
+ interror(3); // Bad addressing mode in ea gen
+ }
+
+ return(OK);
+}
+
+// Undefine dirty macros
+#undef eaNgen
+#undef amN
+#undef aNexattr
+#undef aNexval
+#undef aNexpr
+#undef aNixreg
+#undef aNixsiz
--- /dev/null
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// ERROR.C - Error Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+//
+
+#include "error.h"
+#include "token.h"
+#include "listing.h"
+
+int errcnt; // Error count
+char *err_fname; // Name of error message file
+
+static char nl[] = "\n";
+
+//
+// --- Report error if not at EOL ------------------------------------------------------------------
+//
+
+int at_eol(void) {
+ if(*tok != EOL)
+ error("syntax error");
+ return(0);
+}
+
+//
+// --- Cannot Create a File ------------------------------------------------------------------------
+//
+
+void cantcreat(char *fn) {
+ printf("cannot create: '%s'\n", fn);
+ exit(1);
+}
+
+//
+// --- Setup for Error Message ---------------------------------------------------------------------
+// o Create error listing file (if necessary)
+// o Set current filename
+//
+
+void err_setup(void) {
+ char fnbuf[FNSIZ];
+
+ setfnum(cfileno);
+ if(err_fname != NULL) {
+ strcpy(fnbuf, err_fname);
+ if(*fnbuf == EOS) {
+ strcpy(fnbuf, firstfname);
+ }
+ err_fname = NULL;
+
+ if((err_fd = open(fnbuf, _OPEN_FLAGS, _PERM_MODE)) < 0)
+ cantcreat(fnbuf);
+ err_flag = 1;
+ }
+}
+
+//
+// --- Display Error Message -----------------------------------------------------------------------
+//
+
+int error(char *s) {
+ char buf[EBUFSIZ];
+ unsigned int length;
+
+ err_setup();
+ if(listing > 0) ship_ln(s);
+ sprintf(buf, "%s[%d]: Error: %s%s", curfname, curlineno, s, nl);
+ length = strlen(buf);
+ if(err_flag) write(err_fd, buf, length);
+ else printf("%s", buf);
+ taglist('E');
+ ++errcnt;
+
+ return(ERROR);
+}
+
+int errors(char *s, char *s1) {
+ char buf[EBUFSIZ];
+ char buf1[EBUFSIZ];
+
+ err_setup();
+ sprintf(buf, s, s1);
+ if(listing > 0) ship_ln(buf);
+ sprintf(buf1, "%s[%d]: Error: %s%s", curfname, curlineno, buf, nl);
+ if(err_flag) write(err_fd, buf1, (LONG)strlen(buf1));
+ else printf("%s", buf1);
+ taglist('E');
+ ++errcnt;
+
+ return(ERROR);
+}
+
+int warn(char *s) {
+ char buf[EBUFSIZ];
+
+ err_setup();
+ if(listing > 0) ship_ln(s);
+ sprintf(buf, "%s[%d]: Warning: %s%s", curfname, curlineno, s, nl);
+ if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
+ else printf("%s", buf);
+ taglist('W');
+
+ return(OK);
+}
+
+int warns(char *s, char *s1) {
+ char buf[EBUFSIZ];
+ char buf1[EBUFSIZ];
+
+ err_setup();
+ sprintf(buf, s, s1);
+ if(listing > 0) ship_ln(s);
+ sprintf(buf1, "%s[%d]: Warning: %s%s", curfname, curlineno, buf, nl);
+ if(err_flag) write(err_fd, buf1, (LONG)strlen(buf1));
+ else printf("%s", buf1);
+ taglist('W');
+
+ return(OK);
+}
+
+int warni(char *s, unsigned i) {
+ char buf[EBUFSIZ];
+ char buf1[EBUFSIZ];
+
+ err_setup();
+ sprintf(buf, s, i);
+ if(listing > 0) ship_ln(buf);
+ sprintf(buf1, "%s[%d]: Warning: %s%s", curfname, curlineno, buf, nl);
+ if(err_flag) write(err_fd, buf1, (LONG)strlen(buf1));
+ else printf("%s", buf1);
+ taglist('W');
+
+ return(OK);
+}
+
+int fatal(char *s) {
+ char buf[EBUFSIZ];
+
+ err_setup();
+ if(listing > 0) ship_ln(s);
+ sprintf(buf, "%s[%d]: Fatal: %s%s", curfname, curlineno, s, nl);
+ if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
+ else printf("%s", buf);
+
+ exit(1);
+}
+
+int interror(int n) {
+ char buf[EBUFSIZ];
+
+ err_setup();
+ sprintf(buf, "%s[%d]: Internal Error Number %d%s", curfname, curlineno, n, nl);
+ if(listing > 0) ship_ln(buf);
+ if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
+ else printf("%s", buf);
+
+ exit(1);
+}
\ No newline at end of file
--- /dev/null
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// ERROR.H - Error Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+//
+
+#ifndef __ERROR_H__
+#define __ERROR_H__
+
+#include "rmac.h"
+
+#define EBUFSIZ 200 // Max size of an error message
+
+// Globals, externals etc
+extern int errcnt;
+extern char *err_fname;
+
+// Prototypes
+int error(char *);
+int errors(char *, char *);
+int fatal(char *);
+int warn(char *);
+int warns(char *, char *);
+int warni(char *, unsigned);
+int interror(int);
+void cantcreat(char *);
+void err_setup(void);
+
+#endif // __ERROR_H__
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// EXPR.C - Expression Analyzer
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "expr.h"
+#include "token.h"
+#include "listing.h"
+#include "error.h"
+#include "procln.h"
+#include "symbol.h"
+#include "sect.h"
+#include "mach.h"
+#include "risca.h"
+
+#define DEF_KW // Declare keyword values
+#include "kwtab.h" // Incl generated keyword tables & defs
+
+static char tokcl[128]; // Generated table of token classes
+static VALUE evstk[EVSTACKSIZE]; // Evaluator value stack
+static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack
+
+// Token-class initialization list
+char itokcl[] = {
+ 0, // END
+ CONST, SYMBOL, 0, // ID
+ '(', '[', '{', 0, // OPAR
+ ')', ']', '}', 0, // CPAR
+ CR_DEFINED, CR_REFERENCED, // SUNARY (special unary)
+ CR_STREQ, CR_MACDEF,
+ CR_DATE, CR_TIME, 0,
+ '!', '~', UNMINUS, 0, // UNARY
+ '*', '/', '%', 0, // MULT
+ '+', '-', 0, // ADD
+ SHL, SHR, 0, // SHIFT
+ LE, GE, '<', '>', NE, '=', 0, // REL
+ '&', 0, // AND
+ '^', 0, // XOR
+ '|', 0, // OR
+ 1 // (the end)
+};
+
+char missym_error[] = "missing symbol";
+char *str_error = "missing symbol or string";
+
+// Convert expression to postfix
+static TOKEN *tk; // Deposit tokens here
+SYM *lookup();
+SYM *newsym();
+
+//
+// --- Obtain a String Value -----------------------------------------------------------------------
+//
+
+static VALUE str_value(char *p) {
+ VALUE v;
+
+ for(v = 0; *p; ++p)
+ v = (v << 8) | (*p & 0xff);
+ return(v);
+}
+
+//
+// --- Initialize Expression Analyzer --------------------------------------------------------------
+//
+
+void init_expr(void) {
+ int i; // Iterator
+ char *p; // Token pointer
+
+ // Initialize token-class table
+ for(i = 0; i < 128; ++i) // Mark all entries END
+ tokcl[i] = END;
+
+ for(i = 0, p = itokcl; *p != 1; ++p)
+ if(*p == 0)
+ ++i;
+ else
+ tokcl[(int)(*p)] = (char)i;
+}
+
+//
+// --- Binary operators (all the same precedence) --------------------------------------------------
+//
+
+int expr0(void) {
+ TOKEN t;
+
+ if(expr1() != OK)
+ return(ERROR);
+ while(tokcl[*tok] >= MULT) {
+ t = *tok++;
+ if(expr1() != OK)
+ return(ERROR);
+ *tk++ = t;
+ }
+ return(OK);
+}
+
+//
+// --- Unary operators (detect unary '-') ----------------------------------------------------------
+//
+
+int expr1(void) {
+ int class;
+ TOKEN t;
+ SYM *sy;
+ char *p, *p2;
+ WORD w;
+ int j;
+
+ class = tokcl[*tok];
+
+ if(*tok == '-' || class == UNARY) {
+ t = *tok++;
+ if(expr2() != OK)
+ return(ERROR);
+ if(t == '-')
+ t = UNMINUS;
+ *tk++ = t;
+ } else if(class == SUNARY)
+ switch((int)*tok++) {
+ case CR_TIME:
+ *tk++ = CONST;
+ *tk++ = dos_time();
+ break;
+ case CR_DATE:
+ *tk++ = CONST;
+ *tk++ = dos_date();
+ break;
+ case CR_MACDEF: // ^^macdef <macro-name>
+ if(*tok++ != SYMBOL) return(error(missym_error));
+ p = (char *)*tok++;
+ if(lookup(p, MACRO, 0) == NULL) w = 0;
+ else w = 1;
+
+ *tk++ = CONST;
+ *tk++ = (TOKEN)w;
+ break;
+ case CR_DEFINED:
+ w = DEFINED;
+ goto getsym;
+ case CR_REFERENCED:
+ w = REFERENCED;
+
+ getsym:
+
+ if(*tok++ != SYMBOL) return(error(missym_error));
+ p = (char *)*tok++;
+ j = 0;
+ if(*p == '.') j = curenv;
+ if((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w)) w = 1;
+ else w = 0;
+
+ *tk++ = CONST;
+ *tk++ = (TOKEN)w;
+ break;
+ case CR_STREQ:
+ if(*tok != SYMBOL && *tok != STRING) return(error(str_error));
+ p = (char *)tok[1];
+ tok +=2;
+
+ if(*tok++ != ',') return(error(comma_error));
+
+ if(*tok != SYMBOL && *tok != STRING) return(error(str_error));
+ p2 = (char *)tok[1];
+ tok += 2;
+
+ w = (WORD)(!strcmp(p, p2));
+ *tk++ = CONST;
+ *tk++ = (TOKEN)w;
+ break;
+ }
+ else
+ return(expr2());
+
+ return(OK);
+}
+
+//
+// --- Terminals (CONSTs) and parenthesis grouping -------------------------------------------------
+//
+
+int expr2(void) {
+ char *p;
+ SYM *sy;
+ int j;
+
+ switch((int)*tok++) {
+ case CONST:
+ *tk++ = CONST;
+ *tk++ = *tok++;
+ break;
+ case SYMBOL:
+ p = (char *)*tok++;
+ j = 0;
+ if(*p == '.')
+ j = curenv;
+ sy = lookup(p, LABEL, j);
+ if(sy == NULL)
+ sy = newsym(p, LABEL, j);
+
+ if(sy->sattre & EQUATEDREG) { // Check register bank usage
+ if((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
+ warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
+ if((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
+ warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
+ }
+
+ *tk++ = SYMBOL;
+ *tk++ = (TOKEN)sy;
+ break;
+ case STRING:
+ *tk++ = CONST;
+ *tk++ = str_value((char *)*tok++);
+ break;
+ case '(':
+ if(expr0() != OK)
+ return(ERROR);
+ if(*tok++ != ')')
+ return(error("missing close parenthesis ')'"));
+ break;
+ case '[':
+ if(expr0() != OK)
+ return(ERROR);
+ if(*tok++ != ']')
+ return(error("missing close parenthesis ']'"));
+ break;
+ case '$':
+ *tk++ = ACONST; // Attributed const
+ *tk++ = sloc; // Current location
+ *tk++ = cursect | DEFINED; // Store attribs
+ break;
+ case '*':
+ *tk++ = ACONST; // Attributed const
+ if(orgactive)
+ *tk++ = orgaddr;
+ else
+ *tk++ = pcloc; // Location at start of line
+ *tk++ = ABS | DEFINED; // Store attribs
+ break;
+ default:
+ return(error("bad expression"));
+ }
+ return(OK);
+}
+
+//
+// --- Recursive-descent expression analyzer (with some simple speed hacks) ------------------------
+//
+
+int expr(TOKEN *otk, VALUE *a_value, WORD *a_attr, SYM **a_esym) {
+ SYM *sy;
+ char *p;
+ int j;
+
+ tk = otk;
+
+ // Optimize for single constant or single symbol.
+ if((tok[1] == EOL) ||
+ (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31)) &&
+ (tokcl[tok[2]] < UNARY))) {
+
+ if(*tok >= KW_R0 && *tok <= KW_R31) {
+ *tk++ = CONST;
+ *tk++ = *a_value = (*tok - KW_R0);
+ *a_attr = ABS | DEFINED;
+ if(a_esym != NULL)
+ *a_esym = NULL;
+ tok++;
+ *tk++ = ENDEXPR;
+ return(OK);
+ } else if(*tok == CONST) {
+ *tk++ = CONST;
+ *tk++ = *a_value = tok[1];
+ *a_attr = ABS | DEFINED;
+ if(a_esym != NULL)
+ *a_esym = NULL;
+ } else if(*tok == '*') {
+ *tk++ = CONST;
+ if(orgactive)
+ *tk++ = *a_value = orgaddr;
+ else
+ *tk++ = *a_value = pcloc;
+ *a_attr = ABS | DEFINED;
+ //*tk++ =
+ if(a_esym != NULL)
+ *a_esym = NULL;
+ tok--;
+ } else {
+ p = (char *)tok[1];
+ j = 0;
+ if(*p == '.')
+ j = curenv;
+ sy = lookup(p, LABEL, j);
+
+ if(sy == NULL)
+ sy = newsym(p, LABEL, j);
+ sy->sattr |= REFERENCED;
+
+ if(sy->sattre & EQUATEDREG) { // Check register bank usage
+ if((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
+ warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
+ if((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
+ warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
+ }
+
+ *tk++ = SYMBOL;
+ *tk++ = (TOKEN)sy;
+
+ if(sy->sattr & DEFINED)
+ *a_value = sy->svalue;
+ else *a_value = 0;
+
+ if(sy->sattre & EQUATEDREG)
+ *a_value &= 0x1F;
+
+ *a_attr = (WORD)(sy->sattr & ~GLOBAL);
+
+ if((sy->sattr & (GLOBAL|DEFINED)) == GLOBAL && a_esym != NULL) {
+ *a_esym = sy;
+ }
+ }
+ tok += 2;
+ *tk++ = ENDEXPR;
+ return(OK);
+ }
+
+ if(expr0() != OK)
+ return(ERROR);
+ *tk++ = ENDEXPR;
+ return(evexpr(otk, a_value, a_attr, a_esym));
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Evaluate expression.
+// If the expression involves only ONE external symbol, the expression is UNDEFINED, but it's value
+// includes everything but the symbol value, and `a_esym' is set to the external symbol.
+// -------------------------------------------------------------------------------------------------
+//
+
+int evexpr(TOKEN *tk, VALUE *a_value, WORD *a_attr, SYM **a_esym) {
+ WORD *sattr;
+ VALUE *sval;
+ WORD attr;
+ SYM *sy;
+ SYM *esym;
+ WORD sym_seg;
+
+ sval = evstk; // (Empty) initial stack
+ sattr = evattr;
+ esym = NULL; // No external symbol involved
+ sym_seg = 0;
+
+ while(*tk != ENDEXPR)
+ switch((int)*tk++) {
+ case SYMBOL:
+ sy = (SYM *)*tk++;
+ sy->sattr |= REFERENCED; // Set "referenced" bit
+
+ if(!(sy->sattr & DEFINED)) {
+ if(!(sy->sattr & GLOBAL)) { // Reference to undefined symbol
+ *a_attr = 0;
+ *a_value = 0;
+ return(OK);
+ }
+ if(esym != NULL) // Check for multiple externals
+ return(error(seg_error));
+ esym = sy;
+ }
+
+ if(sy->sattr & DEFINED) {
+ *++sval = sy->svalue; // Push symbol's value
+ } else {
+ *++sval = 0; // 0 for undefined symbols
+ }
+
+ *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
+ sym_seg = (WORD)(sy->sattr & (TEXT|DATA|BSS));
+ break;
+ case CONST:
+ *++sval = *tk++; // Push value
+ *++sattr = ABS|DEFINED; // Push simple attribs
+ break;
+ case ACONST:
+ *++sval = *tk++; // Push value
+ *++sattr = (WORD)*tk++; // Push attribs
+ break;
+
+ // Binary "+" and "-" matrix:
+ //
+ // ABS Sect Other
+ // ----------------------------
+ // ABS | ABS | Sect | Other |
+ // Sect | Sect | [1] | Error |
+ // Other | Other | Error | [1] |
+ // ----------------------------
+ //
+ // [1] + : Error
+ // - : ABS
+ case '+':
+ --sval; // Pop value
+ --sattr; // Pop attrib
+ *sval += sval[1]; // Compute value
+
+ if(!(*sattr & (TEXT|DATA|BSS)))
+ *sattr = sattr[1];
+ else if(sattr[1] & (TEXT|DATA|BSS))
+ return(error(seg_error));
+ break;
+ case '-':
+ --sval; // Pop value
+ --sattr; // Pop attrib
+ *sval -= sval[1]; // Compute value
+
+ attr = (WORD)(*sattr & (TEXT|DATA|BSS));
+ if(!attr)
+ *sattr = sattr[1];
+ else if(sattr[1] & (TEXT|DATA|BSS)) {
+ if(!(attr & sattr[1])) {
+ return(error(seg_error));
+ } else {
+ *sattr &= ~(TEXT|DATA|BSS);
+ }
+ }
+ break;
+ // Unary operators only work on ABS items
+ case UNMINUS:
+ if(*sattr & (TEXT|DATA|BSS))
+ error(seg_error);
+ *sval = -(int)*sval;
+ *sattr = ABS|DEFINED; // Expr becomes absolute
+ break;
+ case '!':
+ if(*sattr & (TEXT|DATA|BSS))
+ error(seg_error);
+ *sval = !*sval;
+ *sattr = ABS|DEFINED; // Expr becomes absolute
+ break;
+ case '~':
+ if(*sattr & (TEXT|DATA|BSS))
+ error(seg_error);
+ *sval = ~*sval;
+ *sattr = ABS|DEFINED; // Expr becomes absolute
+ break;
+ // Comparison operators must have two values that
+ // are in the same segment, but that's the only requirement.
+ case LE:
+ --sattr;
+ --sval;
+ if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
+ *sattr = ABS|DEFINED;
+ *sval = *sval <= sval[1];
+ break;
+ case GE:
+ --sattr;
+ --sval;
+ if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
+ *sattr = ABS|DEFINED;
+ *sval = *sval >= sval[1];
+ break;
+ case '>':
+ --sattr;
+ --sval;
+ if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
+ *sattr = ABS|DEFINED;
+ *sval = *sval > sval[1];
+ break;
+ case '<':
+ --sattr;
+ --sval;
+ if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
+ *sattr = ABS|DEFINED;
+ *sval = *sval < sval[1];
+ break;
+ case NE:
+ --sattr;
+ --sval;
+ if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
+ *sattr = ABS|DEFINED;
+ *sval = *sval != sval[1];
+ break;
+ case '=':
+ --sattr;
+ --sval;
+ if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
+ *sattr = ABS|DEFINED;
+ *sval = *sval == sval[1];
+ break;
+ // All other binary operators must have two ABS items
+ // to work with. They all produce an ABS value.
+ default:
+ // GH - Removed for v1.0.15 as part of the fix for indexed loads.
+ //if((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
+ //error(seg_error);
+
+ *sattr = ABS|DEFINED; // Expr becomes absolute
+ switch((int)tk[-1]) {
+ case '*':
+ --sval;
+ --sattr; // Pop attrib
+ *sval *= sval[1];
+ break;
+ case '/':
+ --sval;
+ --sattr; // Pop attrib
+ if(sval[1] == 0)
+ return(error("divide by zero"));
+ *sval /= sval[1];
+ break;
+ case '%':
+ --sval;
+ --sattr; // Pop attrib
+ if(sval[1] == 0)
+ return(error("mod (%) by zero"));
+ *sval %= sval[1];
+ break;
+ case SHL:
+ --sval;
+ --sattr; // Pop attrib
+ *sval <<= sval[1];
+ break;
+ case SHR:
+ --sval;
+ --sattr; // Pop attrib
+ *sval >>= sval[1];
+ break;
+ case '&':
+ --sval;
+ --sattr; // Pop attrib
+ *sval &= sval[1];
+ break;
+ case '^':
+ --sval;
+ --sattr; // Pop attrib
+ *sval ^= sval[1];
+ break;
+ case '|':
+ --sval;
+ --sattr; // Pop attrib
+ *sval |= sval[1];
+ break;
+ default:
+ interror(5); // Bad operator in expression stream
+ }
+ }
+
+ if(esym != NULL) *sattr &= ~DEFINED;
+ if(a_esym != NULL) *a_esym = esym;
+
+ // sym_seg added in 1.0.16 to solve a problem with forward symbols in expressions where absolute
+ // values also existed. The absolutes were overiding the symbol segments and not being included :(
+ //*a_attr = *sattr | sym_seg; // Copy value + attrib
+
+ *a_attr = *sattr; // Copy value + attrib
+ *a_value = *sval;
+
+ return(OK);
+}
+
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// EXPR.H - Expression Analyzer
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __EXPR_H__
+#define __EXPR_H__
+
+#include "rmac.h"
+
+// Tunable definitions
+#define STKSIZE 64 // Size of expression stacks
+#define EVSTACKSIZE 64 // Expression evaluator stack size
+
+// Token classes in order of precedence
+#define END 0 // End/beginning of input
+#define ID 1 // Symbol or constant
+#define OPAR 2 // (
+#define CPAR 3 // )
+#define SUNARY 4 // Special unary (^^defined, etc.)
+#define UNARY 5 // Unary class: ! ~ -
+#define MULT 6 // Multiplicative class: * / %
+#define ADD 7 // Additive class: + -
+#define SHIFT 8 // Shift class: << >>
+#define REL 9 // Relational class: <= >= < > <> = !=
+#define AND 10 // Bitwise and: &
+#define XOR 11 // Bitwise xor: ^
+#define OR 12 // Bitwise or: |
+
+// Prototypes
+void init_expr(void);
+int expr1(void);
+int expr2(void);
+int expr(TOKEN *, VALUE *, WORD *, SYM **);
+int evexpr(TOKEN *, VALUE *, WORD *, SYM **);
+
+#endif // __EXPR_H__
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// KWGEN.C - Keyword & Mnemonic Definition and State Machine Creation Tool
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+/*
+ * keyword transition-table generation utility
+ *
+ *
+ *----------------
+ *
+ * SYNOPSIS: kw basename <file1 >file2
+ *
+ * `-d' turns on debugging messages
+ *
+ * Accepts a list of keywords and corresponding values. Lines
+ * beginning with '#' are comments. Values may be empty (resulting
+ * in a default value of the previous item's value plus 1, or zero
+ * if there is no previous item), decimal numbers, or characters
+ * enclosed between single quotes.
+ *
+ * # this is a comment
+ * .byte 34
+ * .word 'A'
+ * .long
+ *
+ * The `basename' is a string prepended to the beginning of each of
+ * the output array names, and should be one or two characters.
+ *
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Tunable definitions
+ *
+ */
+#define TABSIZE 1024 /* state table size */
+#define NSTRINGS 500 /* maximum number of keywords */
+#define STRPOOLSIZ (NSTRINGS * 10) /* size of string pool */
+
+
+/*
+ * Do not change these
+ */
+#define EOS '\0' /* null */
+#define UNUSED -1 /* slot in ktab[] is unused */
+#define MARKED -2 /* slot in ktab[] is used, not assigned yet */
+
+
+/*
+ * Table-building tables
+ */
+int kmax = 0; /* largest index into ktab */
+int ktab[TABSIZE]; /* next state number (or -1) */
+int kcheck[TABSIZE]; /* check state number (or -1) */
+int kaccept[TABSIZE]; /* accept (or -1) */
+int kbase[TABSIZE]; /* ktab[] index for a state `i' */
+int nstates; /* number of states in kbase[] */
+
+/*
+ * Temporary tables
+ */
+int tab[128]; /* tmp table for building ktab[] */
+int accept[128]; /* tmp table for building accept[] */
+
+struct name_entry {
+ char *nstr; /* -> name string */
+ int nval; /* = name's value */
+} namtab[NSTRINGS];
+
+int nnames; /* number of keywords */
+char strpool[STRPOOLSIZ]; /* pool for keyword text */
+char *basename; /* -> string to prepend to array names */
+char uppername[100]; /* all-uppercase version of basename */
+int debug = 0; /* 1, enable debugging messages */
+
+int comp_entry();
+void panic(char *);
+int nmatch(int, char *, char *);
+void wiredown(void);
+void print_tables(void);
+void dumptab(char *, char *, int *, int);
+void traverse(int);
+
+int main(int argc, char **argv) {
+ register int i, /*j,*/ k, w;
+ char *s, *s1;
+ int found1;
+ int valid = 0;
+ //int base;
+ int state;
+
+ if (argc != 2)
+ {
+ panic("bad commandline");
+ }
+
+ basename = argv[1];
+ for (s = basename, s1 = uppername; *s; ++s, ++s1)
+ *s1 = (char)toupper(*s);
+ *s1 = EOS;
+
+ /*
+ * init tables
+ */
+ for (i = 0; i < TABSIZE; ++i)
+ {
+ ktab[i] = -1;
+ kcheck[i] = -1;
+ kaccept[i] = -1;
+ }
+ nstates = 0;
+
+ /*
+ * read keyword list
+ *
+ */
+ s = strpool;
+ while (gets(s) != NULL)
+ {
+ if (*s == '#' || !*s) /* ignore comment and empty lines */
+ continue;
+
+ namtab[nnames].nstr = s;
+ while (*s && !isspace(*s))
+ ++s;
+
+ if (!*s)
+ {
+ ++s;
+ goto empty;
+ }
+
+ if (*s && isspace(*s))
+ *s++ = '\0';
+
+ s1 = s;
+ while (*s1 && isspace(*s1))
+ ++s1;
+
+ if (!*s1)
+ {
+empty: /* use previous entry + 1 */
+ if (!nnames) /* complain if no previous entry */
+ namtab[nnames].nval = 0;
+ else namtab[nnames].nval = namtab[nnames-1].nval + 1;
+ }
+ else if (isdigit(*s1))
+ namtab[nnames].nval = atoi(s1);
+ else if (*s1 == '\'')
+ namtab[nnames].nval = *++s1;
+ else if (*s1 == '=')
+ { /* same as previous entry */
+ if (!nnames) /* zero for first entry */
+ namtab[nnames].nval = 0;
+ else namtab[nnames].nval = namtab[nnames-1].nval;
+ }
+ else
+ {
+ fprintf(stderr, "bad expression at '%s'\n", namtab[nnames].nstr);
+ exit(1);
+ }
+
+ ++nnames;
+ if (nnames >= NSTRINGS)
+ panic("name table overflow");
+ if (s >= &strpool[STRPOOLSIZ-100])
+ panic("string table overflow");
+ }
+
+ qsort(namtab, nnames, sizeof(struct name_entry), comp_entry);
+
+ /*
+ * compute table start indices
+ */
+ found1 = 1;
+
+ for (k = 1; found1; ++k)
+ {
+ found1 = 0;
+
+ for (w = 0; w <= nnames; ++w)
+ {
+ if (w == 0 ||
+ w == nnames ||
+ !nmatch(k-1, namtab[w].nstr, namtab[w-1].nstr))
+ {
+ if (w != 0 &&
+ valid != 0)
+ {
+ wiredown();
+
+ if (k > 1)
+ {
+ state = 0;
+ for (i = 0; i < k-2; ++i)
+ {
+ if (ktab[kbase[state] + *(namtab[w-1].nstr + i)] < 0)
+ panic("table build error");
+ else state = ktab[kbase[state] +
+ *(namtab[w-1].nstr + i)];
+ }
+
+ ktab[kbase[state] + *(namtab[w-1].nstr + k-2)] = nstates;
+ }
+ ++nstates;
+ found1 = 1;
+ }
+
+ for (i = 0; i < 128; ++i)
+ {
+ tab[i] = UNUSED;
+ accept[i] = -1;
+ }
+
+ valid = 0;
+ }
+
+ if ( w >= nnames ||
+ (int)strlen(namtab[w].nstr) < k)
+ {
+ continue;
+ }
+
+ tab[*(namtab[w].nstr + k-1)] = MARKED;
+ if (*(namtab[w].nstr + k) == '\0')
+ {
+ accept[*(namtab[w].nstr + k-1)] = namtab[w].nval;
+ }
+ valid = 1;
+ }
+ }
+
+ traverse(0);
+ print_tables();
+
+ return 0;
+}
+
+
+/*
+ * find position for set of characters;
+ *
+ */
+void wiredown(void) {
+ register int base;
+ register int i;
+
+ for (base = 0; base < TABSIZE-128; ++base)
+ {
+ for (i = 0; i < 128; ++i)
+ if (ktab[base+i] != UNUSED &&
+ tab[i] == MARKED)
+ break;
+ if (i >= 128)
+ break;
+ }
+
+ if (base >= TABSIZE-128)
+ panic("Cannot build table (won't fit in tables)\n");
+
+ for (i = 0; i < 128; ++i)
+ if (tab[i] == MARKED)
+ {
+ ktab[base + i] = MARKED;
+ kaccept[base + i] = accept[i];
+ kcheck[base + i] = nstates;
+ }
+ kbase[nstates] = base;
+
+ if (kmax < base)
+ kmax = base;
+}
+
+
+void print_tables(void) {
+// int i;
+
+ printf("\n#ifdef DECL_%s\n", uppername);
+ printf("/*\n * keyword state-machine tables\n *\n */\n");
+ dumptab("base", basename, kbase, nstates);
+ dumptab("tab", basename, ktab, kmax + 128);
+ dumptab("check", basename, kcheck, kmax + 128);
+ dumptab("accept", basename, kaccept, kmax + 128);
+ printf("#endif\n");
+}
+
+
+void dumptab(char *tabname, char *tabprefix, int *table, int tabsize) {
+ int i, j;
+
+ printf("\nint %s%s[%d] = {\n",
+ tabprefix, tabname, tabsize);
+
+ for (i = j = 0; i < tabsize; ++i)
+ {
+ printf(" %d", table[i]);
+ if (i != tabsize-1)
+ putchar(',');
+ if (++j == 8)
+ {
+ j = 0;
+ putchar('\n');
+ }
+ }
+ if (j)
+ putchar('\n');
+ printf("};\n");
+}
+
+
+int comp_entry(struct name_entry *ent1, struct name_entry *ent2) {
+ return strcmp(ent1->nstr, ent2->nstr);
+}
+
+
+int nmatch(int len, char *s1, char *s2) {
+ while (len--)
+ if (*s1++ != *s2++)
+ return 0;
+ return 1;
+}
+
+
+char nam[128];
+char *pnam;
+
+void traverse(int state) {
+ register int base, i;//, j;
+ char *s, c;
+
+ if (state == 0)
+ {
+ printf("#ifdef DEF_%s\n", uppername);
+ printf("/*\n * Keyword definitions\n */\n");
+ pnam = nam;
+ *pnam = 0;
+ }
+
+ base = kbase[state];
+ for (i = 0; i < 128; ++i)
+ if (kcheck[base + i] == state)
+ {
+ *pnam++ = (char)i;
+ *pnam = '\0';
+
+ for (s = nam; *s; ++s)
+ if (isupper(*s))
+ break;
+
+ if (kaccept[base + i] >= 0 &&
+ !isupper(*s))
+ {
+ printf("#define\t%s_", uppername);
+ for (s = nam; (c = *s); ++s)
+ {
+ if (c == '.')
+ c = '_';
+ else if ((c >= 'a') && (c <= 'z'))
+ c -= 32;
+ printf("%c", c);
+ }
+ printf("\t%d\n", kaccept[base + i]);
+ }
+
+ if (ktab[base + i] >= 0)
+ traverse(ktab[base + i]);
+ *--pnam = '\0';
+ }
+
+ if (state == 0)
+ printf("#endif\n");
+}
+
+
+void panic(char *s) {
+ fprintf(stderr, "Panic: %s\n", s);
+ exit(1);
+}
--- /dev/null
+d0 128
+d1 129
+d2 130
+d3 131
+d4 132
+d5 133
+d6 134
+d7 135
+
+a0 136
+a1 137
+a2 138
+a3 139
+a4 140
+a5 141
+a6 142
+a7 143
+
+sp 143
+usp 143
+ssp 144
+pc 145
+sr 146
+ccr 147
+
+.equ 61
+equ 61
+.equr 148
+equr 148
+.regequ 148
+regequ 148
+set 149
+reg 150
+r0 151
+r1 152
+r2 153
+r3 154
+r4 155
+r5 156
+r6 157
+r7 158
+r8 159
+r9 160
+r10 161
+r11 162
+r12 163
+r13 164
+r14 165
+r15 166
+r16 167
+r17 168
+r18 169
+r19 170
+r20 171
+r21 172
+r22 173
+r23 174
+r24 175
+r25 176
+r26 177
+r27 178
+r28 179
+r29 180
+r30 181
+r31 182
+.ccdef 183
+ccdef 183
+defined 112
+referenced 113
+streq 118
+macdef 119
+time 120
+date 121
+
+
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// LISTING.C - Listing Output
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+// -------------------------------------------------------------------------------------------------
+// 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7
+// 012345678901234567890123456789012345678901234567890123456789012345678901234567
+// filename.... Reboot's Macro Assembler N.N.NN (Unknown)
+// nnnnn aaaaaaaa dddddddddddddddddddd T source code
+// nnnnn aaaaaaaa dddddddddddddddd
+// nnnnn =vvvvvvvv
+
+#include "listing.h"
+#include "version.h"
+#include "token.h"
+#include "procln.h"
+#include "sect.h"
+#include "error.h"
+
+char *list_fname; // Listing filename
+char subttl[TITLESIZ]; // Current subtitle
+int listing; // Listing level
+int pagelen = 61; // Lines on a page
+int nlines; // #lines on page so far
+LONG lsloc; // `sloc' at start of line
+
+// Private
+static int lcursect; // `cursect' at start of line
+static int llineno; // `curlineno' at start of line
+static int pageno; // Current page number
+static int pagewidth; // #columns on a page
+static int subflag; // 0, don't do .eject on subttl (set 1)
+static char lnimage[IMAGESIZ]; // Image of output line
+static char title[TITLESIZ]; // Current title
+static char datestr[20]; // Current date dd-mon-yyyy
+static char timestr[20]; // Current time hh:mm:ss [am|pm]
+static char buf[IMAGESIZ]; // Buffer for numbers
+
+static char *month[16] = { "", "Jan", "Feb", "Mar",
+ "Apr", "May", "Jun", "Jul",
+ "Aug", "Sep", "Oct", "Nov",
+ "Dec", "", "", "" };
+
+//
+// --- Eject the Page (Print Empty Lines), Reset the Line Count and Bump the Page Number -----------
+//
+
+int eject(void) {
+ if(listing > 0) {
+ println("\f");
+ nlines = 0;
+ }
+ return(0);
+}
+
+//
+// --- Return GEMDOS Format Date -------------------------------------------------------------------
+//
+
+VALUE dos_date(void) {
+ VALUE v;
+ struct tm *tm;
+ time_t tloc;
+
+ time(&tloc);
+ tm = localtime(&tloc);
+ v = ((tm->tm_year - 80) << 9) | ((tm->tm_mon+1) << 5) | tm->tm_mday;
+
+ return(v);
+}
+
+//
+// --- Return GEMDOS Format Time -------------------------------------------------------------------
+//
+
+VALUE dos_time(void) {
+ VALUE v;
+ struct tm *tm;
+ time_t tloc;
+
+ time(&tloc);
+ tm = localtime(&tloc);
+ v = (tm->tm_hour << 11) | (tm->tm_min) << 5 | tm->tm_sec;
+
+ return(v);
+}
+
+//
+// --- Generate a Time String ----------------------------------------------------------------------
+//
+
+void time_string(char *buf, VALUE time) {
+ int hour;
+ char *ampm;
+
+ hour = (time >> 11);
+ if(hour > 12) {
+ hour -= 12;
+ ampm = "pm";
+ } else ampm = "am";
+
+ sprintf(buf, "%d:%02d:%02d %s",
+ hour, (int)((time >> 5) & 0x3f), (int)((time & 0x1f) << 1), ampm);
+}
+
+//
+// --- Generate a Date String ----------------------------------------------------------------------
+//
+
+void date_string(char *buf, VALUE date) {
+ sprintf(buf, "%d-%s-%d",
+ (int)(date & 0x1f), month[(date >> 5) & 0xf], (int)((date >> 9) + 1980));
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Copy `n' Characters from `src' to `dest' (also stops on EOS in src).
+// Does not null-terminate dest.
+// -------------------------------------------------------------------------------------------------
+//
+
+void scopy(char *dest, char *src, int len) {
+ if(len < 0)
+ len = 1000; // Some large number
+ while(len-- && *src)
+ *dest++ = *src++;
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Transform letters a-f in the address and data columns of the listing to uppercase. (People seem
+// to like uppercase hex better in assembly-language listings....)
+// -------------------------------------------------------------------------------------------------
+//
+
+void uc_ln(char *ln) {
+ int i;
+ char j;
+
+ for(i = LOC_COL; i < SRC_COL; ++i)
+ if((j = ln[i]) >= 'a' && j <= 'f')
+ ln[i] = (char)(j - 0x20);
+}
+
+//
+// --- Fill Region `dest' with `len' Characters `c' and Null Terminate the Region ------------------
+//
+
+void lnfill(char *dest, int len, char chr) {
+ while(len--)
+ *dest++ = chr;
+ *dest = EOS;
+}
+
+//
+// --- Create Listing File with the Appropriate Name -----------------------------------------------
+//
+
+void list_setup(void) {
+ char fnbuf[FNSIZ];
+
+ strcpy(fnbuf, list_fname);
+ if(*fnbuf == EOS) {
+ strcpy(fnbuf, firstfname);
+ fext(fnbuf, ".prn", 1);
+ }
+ list_fname = NULL;
+
+ if((list_fd = open(fnbuf, _OPEN_FLAGS, _PERM_MODE)) < 0)
+ cantcreat(fnbuf);
+}
+
+//
+// --- Tag Listing with a Character, Typically for Errors or Warnings ------------------------------
+
+void taglist(char chr) {
+ lnimage[TAG_COL+1] = chr;
+}
+
+//
+// --- Print a Line to the Listing File ------------------------------------------------------------
+//
+
+void println(char *ln) {
+ unsigned int length;
+
+ if(list_fname != NULL) // Create listing file, if necessary
+ list_setup();
+
+ length = strlen(ln);
+ write(list_fd, ln, length);
+ write(list_fd, "\n", 1L);
+}
+
+//
+// --- Ship Line `ln' Out; Do Page Breaks and Title Stuff ------------------------------------------
+//
+
+void ship_ln(char *ln) {
+ // If listing level is <= 0, then don't print anything
+ if(listing <= 0)
+ return;
+
+ // Notice bottom of page
+ if(nlines >= pagelen - BOT_MAR)
+ eject();
+
+ // Print title, boilerplate, and subtitle at top of page
+ if(nlines == 0) {
+ ++pageno;
+ println("");
+ date_string(datestr, dos_date());
+ time_string(timestr, dos_time());
+ sprintf(buf,
+ "%-40s%-20s Page %-4d %s %s RMAC %01i.%01i.%02i (%s)",
+ title, curfname, pageno, timestr, datestr, MAJOR, MINOR, PATCH, PLATFORM);
+ println(buf);
+ sprintf(buf, "%s", subttl);
+ println(buf);
+ println("");
+ nlines = 4;
+ }
+
+ println(ln);
+ ++nlines;
+}
+
+//
+// --- Initialize Listing Generator ----------------------------------------------------------------
+//
+
+void init_list(void) {
+ extern VALUE dos_date(), dos_time();
+
+ subflag = 0;
+ pageno = 0;
+ nlines = 0;
+ pagelen = 61;
+ pagewidth = 132;
+ strcpy(title, "");
+ strcpy(subttl, "");
+ date_string(datestr, dos_date());
+ time_string(timestr, dos_time());
+}
+
+//
+// --- Listing EOL ---------------------------------------------------------------------------------
+//
+
+void listeol(void) {
+ CHUNK *ch;
+ char *p;
+ int col;
+ LONG count;
+ int fixcount;
+
+ DEBUG printf("~list: lsloc=$%lx sloc=$%lx\n", lsloc, sloc);
+
+ if(lsloc != sloc) {
+ sprintf(buf, "%08lx", lsloc);
+ scopy(lnimage+LOC_COL, buf, 8);
+ }
+
+ if(llineno != curlineno) {
+ sprintf(buf, "%5d", llineno);
+ scopy(lnimage+LN_COL, buf, 5);
+ }
+
+ // List bytes only when section stayed the same and the section is not a "no-data" (SBSS)
+ // section. An extra annoyance is caused by "ds.b" in a microprocessor mode, which prints
+ // out bytes of zero as if they had been deposited with dcb. The fix (kludge) is an extra
+ // variable which records the fact that a 'ds.x' directive generated all the data, and it
+ // shouldn't be listed
+ savsect(); // Update section variables
+ if(lcursect == cursect && (sect[lcursect].scattr & SBSS) == 0 && lsloc != sloc && just_bss==0) {
+ ch = sect[lcursect].sfcode;
+ for(; ch != NULL; ch = ch->chnext)
+ if(lsloc >= ch->chloc && lsloc < (ch->chloc + ch->ch_size))
+ break;
+
+ if(ch == NULL) { // Fatal: Can't find chunk holding code
+
+ nochunk:
+
+ interror(6); // Can't find generated code in section
+ }
+
+ p = ch->chptr + (lsloc - ch->chloc);
+ col = DATA_COL;
+ fixcount = 0;
+ for(count = sloc - lsloc; count--; col += 2, ++lsloc) {
+ if(col >= DATA_END) { // Ship the line
+ col = DATA_COL;
+ uc_ln(lnimage);
+ ship_ln(lnimage);
+ lnfill(lnimage, SRC_COL, SPACE); // Fill with spaces
+ sprintf(buf, "%08lx", lsloc);
+ scopy(lnimage+LOC_COL, buf, 8);
+ }
+
+ if(lsloc >= (ch->chloc + ch->ch_size)) {
+ if((ch = ch->chnext) == NULL)
+ goto nochunk;
+ p = ch->chptr;
+ }
+
+ if(!fixcount)
+ fixcount = fixtest(lcursect, lsloc);
+
+ if(fixcount) {
+ --fixcount;
+ strcpy(buf, "xx");
+ ++p; // Advance anyway
+ } else
+ sprintf(buf, "%02x", *p++ & 0xff);
+ scopy(lnimage+col, buf, 2);
+ }
+
+ if(col > DATA_COL) { // Flush partial line
+ uc_ln(lnimage);
+ ship_ln(lnimage);
+ }
+ } else {
+ uc_ln(lnimage);
+ ship_ln(lnimage);
+ }
+}
+
+//
+// --- Copy Current (Saved) Line to Output Buffer and Tag it with a Character ----------------------
+//
+
+void lstout(char tag) {
+ char *s;
+ char *d;
+
+ lsloc = sloc;
+ lcursect = cursect;
+ llineno = curlineno;
+
+ lnfill(lnimage, SRC_COL, SPACE); // Fill with spaces
+ lnimage[TAG_COL] = tag;
+
+ // Copy line image and handle control characters
+ d = lnimage + SRC_COL;
+ for(s = lnbuf; *s; ++s)
+ if(*s >= 0x20 || *s == '\t')
+ *d++ = *s;
+ else {
+ *d++ = '^';
+ *d++ = (char)(*s + 0x40);
+ }
+ *d++ = EOS;
+}
+
+//
+// --- Output a Value to Listing -------------------------------------------------------------------
+//
+
+int listvalue(VALUE v) {
+ sprintf(buf, "=%08lx", v);
+ scopy(lnimage+DATA_COL-1, buf, 9);
+ return(0);
+}
+
+/*
+ * .subttl [-] "string"
+ *
+ * Set subtitle;
+ * o leading '-' supresses page eject
+ * o don't .eject on first .subttl, but do so on all other ones,
+ * o arrange not to print the .subttl directive
+ *
+ */
+int d_subttl(void) {
+ int ejectok;
+
+ ejectok = 1;
+ if(*tok == '-') {
+ ejectok = 0;
+ ++tok;
+ }
+
+ if(*tok != STRING)
+ return(error("missing string"));
+ strcpy(subttl, (char*)tok[1]);
+
+ tok += 2;
+ if(ejectok && (subflag || pageno > 1)) // Always eject on pages 2+
+ eject();
+ subflag = 1;
+
+ return(0);
+}
+
+//
+// --- Set title on titles not on the first page, do an eject and clobber the subtitle -------------
+//
+
+int d_title(void) {
+ if(*tok != STRING)
+ return(error("missing string"));
+ strcpy(title, (char*)tok[1]);
+ tok += 2;
+
+ if(pageno > 1) {
+ strcpy(subttl, "");
+ eject();
+ }
+
+ return(0);
+}
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// LISTING.H - Listing Output
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __LISTING_H__
+#define __LISTING_H__
+
+#include <time.h>
+#include "rmac.h"
+
+#define BOT_MAR 1 // #blank lines on bottom of page
+#define IMAGESIZ 200 // Max size of a line of text
+#define TITLESIZ 200 // Max size of a title
+#define LN_COL 0 // Column for line numbers
+#define LOC_COL 7 // Location ptr
+#define DATA_COL 17 // Data start (for 20 chars, usually 16)
+#define DATA_END (DATA_COL+20) // End+1th data column
+#define TAG_COL 38 // Tag character
+#define SRC_COL 40 // Source start
+
+// Globals, externals etc
+extern char *list_fname;
+extern int listing;
+extern int pagelen;
+extern int nlines;
+extern LONG lsloc;
+
+// Prototypes
+void init_list(void);
+void ship_ln(char *);
+void taglist(char);
+void println(char *);
+void listeol(void);
+VALUE dos_date(void);
+VALUE dos_time(void);
+void lstout(char);
+int listvalue(VALUE);
+int d_subttl(void);
+int d_title(void);
+
+#endif // __LISTING_H__
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// MACH.C - Code Generation
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "mach.h"
+#include "error.h"
+#include "sect.h"
+#include "direct.h"
+#include "token.h"
+#include "procln.h"
+#include "risca.h"
+
+#define DEF_KW
+#include "kwtab.h"
+
+// Common error messages
+char *range_error = "expression out of range";
+char *abs_error = "illegal absolute expression";
+char *seg_error = "bad (section) expression";
+char *rel_error = "illegal relative address";
+char *siz_error = "bad size specified";
+char *undef_error = "undefined expression";
+char *fwd_error = "forward or undefined expression";
+
+extern int ea0gen(WORD);
+extern int ea1gen(WORD);
+
+// Include code tables
+MNTAB machtab[] = {
+ { (WORD)-1, (unsigned long)-1L, (unsigned long)-1L, 0x0000, 0, m_badmode }, // 0
+ #include "68ktab.h"
+ { 0, 0L, 0L, 0x0000, 0, m_unimp } // Last entry
+};
+
+// Register number << 9
+WORD reg_9[8] = {
+ 0, 1<<9, 2<<9, 3<<9,
+ 4<<9, 5<<9, 6<<9, 7<<9
+};
+
+// SIZB==>00, SIZW==>01, SIZL==>10, SIZN==>01 << 6
+WORD siz_6[] = {
+ (WORD)-1, // n/a
+ 0, // SIZB
+ 1<<6, (WORD)-1, // SIZW, n/a
+ 2<<6, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
+ 1<<6 // SIZN
+};
+
+// Byte/word/long size for MOVE instrs
+WORD siz_12[] = {
+ (WORD)-1,
+ 0x1000, // Byte
+ 0x3000, (WORD)-1, // Word
+ 0x2000, (WORD)-1, (WORD)-1, (WORD)-1, // Long
+ 0x3000 // Word (SIZN)
+};
+
+// Word/long size (0=.w, 1=.l) in bit 8
+WORD lwsiz_8[] = {
+ (WORD)-1, // n/a
+ (WORD)-1, // SIZB
+ 0, (WORD)-1, // SIZW, n/a
+ 1<<8, (WORD)-1, (WORD)-1, (WORD)-1, // SIZL, n/a, n/a, n/a
+ 0 // SIZN
+};
+
+// Addressing mode in bits 6..11 (register/mode fields are reversed)
+WORD am_6[] = {
+ 00000, 01000, 02000, 03000, 04000, 05000, 06000, 07000,
+ 00100, 01100, 02100, 03100, 04100, 05100, 06100, 07100,
+ 00200, 01200, 02200, 03200, 04200, 05200, 06200, 07200,
+ 00300, 01300, 02300, 03300, 04300, 05300, 06300, 07300,
+ 00400, 01400, 02400, 03400, 04400, 05400, 06400, 07400,
+ 00500, 01500, 02500, 03500, 04500, 05500, 06500, 07500,
+ 00600, 01600, 02600, 03600, 04600, 05600, 06600, 07600,
+ 00700, 01700, 02700, 03700, 04700, 05700, 06700, 07700
+};
+
+// Error messages
+int m_unimp(void) { return((int)error("unimplemented mnemonic")); }
+int m_badmode(void) { return((int)error("inappropriate addressing mode")); }
+
+int m_self(WORD inst) { D_word(inst); return(0);}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Do one EA in bits 0..5
+//
+// Bits in `inst' have the following meaning:
+//
+// Bit zero specifies which ea (ea0 or ea1) to generate in the lower six bits of the instr.
+//
+// If bit one is set, the OTHER ea (the one that wasn't generated by bit zero) is generated after
+// the instruction. Regardless of bit 0's value, ea0 is always deposited in memory before ea1.
+//
+// If bit two is set, standard size bits are set in the instr in bits 6 and 7.
+//
+// If bit four is set, bit three specifies which eaXreg to place in bits 9..11 of the instr.
+// -------------------------------------------------------------------------------------------------
+//
+
+int m_ea(WORD inst, WORD siz) {
+ WORD flg;
+
+ flg = inst; // Save flag bits
+ inst &= ~0x3f; // Clobber flag bits in instr
+
+ if(flg & 4) // Install "standard" instr size bits
+ inst |= siz_6[siz];
+
+ if(flg & 16) { // OR-in register number
+ if(flg & 8) {
+ inst |= reg_9[a1reg]; // ea1reg in bits 9..11
+ } else {
+ inst |= reg_9[a0reg]; // ea0reg in bits 9..11
+ }
+ }
+
+ if(flg & 1) { // Use am1
+ inst |= am1 | a1reg; // Get ea1 into instr
+ D_word(inst); // Deposit instr
+ if(flg & 2) // Generate ea0 if requested
+ ea0gen(siz);
+ ea1gen(siz); // Generate ea1
+ } else { // Use am0
+ inst |= am0 | a0reg; // Get ea0 into instr
+ D_word(inst); // Deposit instr
+ ea0gen(siz); // Generate ea0
+ if(flg & 2) // Generate ea1 if requested
+ ea1gen(siz);
+ }
+
+ return(0);
+}
+
+//
+// --- Dx,Dy nnnnXXXnssnnnYYY If bit 0 of `inst' is set, install size bits in bits 6..7 ------------
+//
+
+int m_abcd(WORD inst, WORD siz) {
+ if(inst & 1) { // Install size bits
+ --inst;
+ inst |= siz_6[siz];
+ }
+
+ inst |= a0reg | reg_9[a1reg];
+ D_word(inst);
+
+ return(0);
+}
+
+//
+// --- {adda} ea,AREG ------------------------------------------------------------------------------
+//
+
+int m_adda(WORD inst, WORD siz) {
+ inst |= am0 | a0reg | lwsiz_8[siz] | reg_9[a1reg];
+ D_word(inst);
+ ea0gen(siz); // Gen EA
+
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// If bit 0 of `inst' is 1, install size bits in bits 6..7 of instr.
+// If bit 1 of `inst' is 1, install a1reg in bits 9..11 of instr.
+// -------------------------------------------------------------------------------------------------
+//
+
+int m_reg(WORD inst, WORD siz) {
+ if(inst & 1) // Install size bits
+ inst |= siz_6[siz];
+ if(inst & 2) // Install other register (9..11)
+ inst |= reg_9[a1reg];
+
+ inst &= ~7; // Clear off crufty bits
+ inst |= a0reg; // Install first register
+ D_word(inst);
+
+ return(0);
+}
+
+//
+// --- <op> #expr ----------------------------------------------------------------------------------
+//
+
+int m_imm(WORD inst, WORD siz) {
+ D_word(inst);
+ ea0gen(siz);
+
+ return(0);
+}
+
+//
+// --- <op>.b #expr --------------------------------------------------------------------------------
+//
+
+int m_imm8(WORD inst, WORD siz) {
+ siz = siz;
+ D_word(inst);
+ ea0gen(SIZB);
+
+ return(0);
+}
+
+//
+// --- <shift> Dn,Dn -------------------------------------------------------------------------------
+//
+
+int m_shr(WORD inst, WORD siz) {
+ inst |= reg_9[a0reg] | a1reg | siz_6[siz];
+ D_word(inst);
+
+ return(0);
+}
+
+//
+// --- <shift> #n,Dn -------------------------------------------------------------------------------
+//
+
+int m_shi(WORD inst, WORD siz) {
+ inst |= a1reg | siz_6[siz];
+
+ if(a0exattr & DEFINED) {
+ if(a0exval > 8)
+ return(error(range_error));
+ inst |= (a0exval & 7) << 9;
+ D_word(inst);
+ } else {
+ fixup(FU_QUICK, sloc, a0expr);
+ D_word(inst);
+ }
+
+ return(0);
+}
+
+//
+// --- {bset, btst, bchg, bclr} -- #immed,ea -- Dn,ea ----------------------------------------------
+//
+
+int m_bitop(WORD inst, WORD siz) {
+ // Enforce instruction sizes
+ if(am1 == DREG) { // X,Dn must be .n or .l
+ if(siz & (SIZB|SIZW))
+ return(error(siz_error));
+ } else
+ if(siz & (SIZW|SIZL)) // X,ea must be .n or .b
+ return error(siz_error);
+
+ // Construct instr and EAs
+ inst |= am1 | a1reg;
+ if(am0 == IMMED) {
+ D_word(inst);
+ ea0gen(SIZB); // Immediate bit number
+ } else {
+ inst |= reg_9[a0reg];
+ D_word(inst);
+ }
+
+ ea1gen(SIZB); // ea to bit-munch
+
+ return(0);
+}
+
+int m_dbra(WORD inst, WORD siz) {
+ VALUE v;
+
+ siz = siz;
+ inst |= a0reg;
+ D_word(inst);
+ if(a1exattr & DEFINED) {
+ if((a1exattr & TDB) != cursect)
+ return(error(rel_error));
+ v = a1exval - sloc;
+
+ if(v + 0x8000 > 0x10000)
+ return(error(range_error));
+ D_word(v);
+ } else {
+ fixup(FU_WORD|FU_PCREL|FU_ISBRA, sloc, a1expr);
+ D_word(0);
+ }
+
+ return(0);
+}
+
+//
+// --- EXG -----------------------------------------------------------------------------------------
+//
+
+int m_exg(WORD inst, WORD siz) {
+ int m;
+
+ siz = siz;
+ if(am0 == DREG && am1 == DREG)
+ m = 0x0040; // Dn,Dn
+ else if(am0 == AREG && am1 == AREG)
+ m = 0x0048; // An,An
+ else {
+ if(am0 == AREG) { // Dn,An or An,Dn
+ m = a1reg; // Get AREG into a1reg
+ a1reg = a0reg;
+ a0reg = m;
+ }
+ m = 0x0088;
+ }
+ inst |= m | reg_9[a0reg] | a1reg;
+ D_word(inst);
+
+ return(0);
+}
+
+//
+// --- LINK ----------------------------------------------------------------------------------------
+//
+
+int m_link(WORD inst, WORD siz) {
+ siz = siz;
+ inst |= a0reg;
+ D_word(inst);
+ ea1gen(SIZW);
+
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Handle MOVE <C_ALL> <C_ALTDATA>
+// MOVE <C_ALL> <M_AREG>
+//
+// Optimize MOVE.L #<smalldata>,D0 to a MOVEQ
+// -------------------------------------------------------------------------------------------------
+//
+
+int m_move(WORD inst, int siz) {
+ // Try to optimize to MOVEQ
+ if(siz == SIZL && am0 == IMMED && am1 == DREG && (a0exattr & (TDB|DEFINED)) == DEFINED &&
+ a0exval + 0x80 < 0x100) {
+ m_moveq((WORD)0x7000, (WORD)0);
+ } else {
+ inst |= siz_12[siz] | am_6[am1] | reg_9[a1reg] | am0 | a0reg;
+
+ D_word(inst);
+ if(am0 >= ADISP) ea0gen((WORD)siz);
+ if(am1 >= ADISP) ea1gen((WORD)siz);
+ }
+
+ return(0);
+}
+
+//
+// --- move USP,An -- move An,USP ------------------------------------------------------------------
+//
+
+int m_usp(WORD inst, WORD siz) {
+ siz = siz;
+ if(am0 == AM_USP) inst |= a1reg; // USP,An
+ else inst |= a0reg; // An,USP
+ D_word(inst);
+
+ return(0);
+}
+
+//
+// --- moveq ---------------------------------------------------------------------------------------
+//
+
+int m_moveq(WORD inst, WORD siz) {
+ siz = siz;
+ if(!(a0exattr & DEFINED)) { // Arrange for future fixup
+ fixup(FU_BYTE|FU_SEXT, sloc+1, a0expr);
+ a0exval = 0;
+ } else
+ if(a0exval + 0x100 >= 0x200)
+ return(error(range_error));
+
+ inst |= reg_9[a1reg] | (a0exval & 0xff);
+ D_word(inst);
+
+ return(0);
+}
+
+//
+// --- movep Dn,disp(An) -- movep disp(An),Dn ------------------------------------------------------
+//
+
+int m_movep(WORD inst, WORD siz) {
+ //WORD k;
+
+ if(siz == SIZL)
+ inst |= 0x0040;
+
+ if(am0 == DREG) {
+ inst |= reg_9[a0reg] | a1reg;
+ D_word(inst);
+ if(am1 == AIND) {
+ D_word(0);
+ } else
+ ea1gen(siz);
+ } else {
+ inst |= reg_9[a1reg] | a0reg;
+ D_word(inst);
+ if(am0 == AIND) {
+ D_word(0);
+ } else
+ ea0gen(siz);
+ }
+
+ return(0);
+}
+
+//
+// --- Bcc -- BSR ----------------------------------------------------------------------------------
+//
+
+int m_br(WORD inst, WORD siz) {
+ VALUE v;
+
+ if(a0exattr & DEFINED) {
+ if((a0exattr & TDB) != cursect)
+ return(error(rel_error));
+
+ v = a0exval - (sloc + 2);
+
+ // Optimize branch instr. size
+ if(siz == SIZN) {
+ if(v != 0 && v + 0x80 < 0x100) { // Fits in .B
+ inst |= v & 0xff;
+ D_word(inst);
+ return(0);
+ } else { // Fits in .W
+ if(v + 0x8000 > 0x10000)
+ return(error(range_error));
+ D_word(inst);
+ D_word(v);
+ return(0);
+ }
+ }
+
+ if(siz == SIZB) {
+ if(v + 0x80 >= 0x100)
+ return(error(range_error));
+ inst |= v & 0xff;
+ D_word(inst);
+ } else {
+ if(v + 0x8000 >= 0x10000)
+ return(error(range_error));
+ D_word(inst);
+ D_word(v);
+ }
+ return(0);
+ } else
+ if(siz == SIZN)
+ siz = SIZW;
+
+ if(siz == SIZB) { // .B
+ fixup(FU_BBRA|FU_PCREL|FU_SEXT, sloc, a0expr);
+ D_word(inst);
+ return(0);
+ } else { // .W
+ D_word(inst);
+ fixup(FU_WORD|FU_PCREL|FU_LBRA|FU_ISBRA, sloc, a0expr);
+ D_word(0);
+ }
+
+ return(0);
+}
+
+//
+// --- ADDQ -- SUBQ --------------------------------------------------------------------------------
+//
+
+int m_addq(WORD inst, WORD siz) {
+ inst |= siz_6[siz] | am1 | a1reg;
+
+ if(a0exattr & DEFINED) {
+ if(a0exval > 8 || a0exval == 0) // Range in 1..8
+ return(error(range_error));
+ inst |= (a0exval & 7) << 9;
+ D_word(inst);
+ } else {
+ fixup(FU_QUICK, sloc, a0expr);
+ D_word(inst);
+ }
+ ea1gen(siz);
+
+ return(0);
+}
+
+//
+// --- trap #n -------------------------------------------------------------------------------------
+//
+
+int m_trap(WORD inst, WORD siz) {
+ siz = siz;
+ if(a0exattr & DEFINED) {
+ if(a0exattr & TDB)
+ return(error(abs_error));
+ if(a0exval >= 16)
+ return(error(range_error));
+ inst |= a0exval;
+ D_word(inst);
+ } else
+ return(error(undef_error));
+
+ return(0);
+}
+
+//
+// --- movem <rlist>,ea -- movem ea,<rlist> --------------------------------------------------------
+//
+
+int m_movem(WORD inst, WORD siz) {
+ VALUE eval;
+ WORD i;
+ WORD w;
+ WORD rmask;
+
+ if(siz & SIZB) return(error("bad size suffix"));
+
+ if(siz == SIZL) inst |= 0x0040;
+
+ if(*tok == '#') { // Handle #<expr>,ea
+ ++tok;
+ if(abs_expr(&eval) != OK) return(0);
+ if(eval >= 0x10000L) return(error(range_error));
+ rmask = (WORD)eval;
+ goto immed1;
+ }
+
+ if(*tok >= KW_D0 && *tok <= KW_A7) { // <rlist>,ea
+ if(reglist(&rmask) < 0) return(0);
+
+ immed1:
+
+ if(*tok++ != ',') return(error("missing comma"));
+ if(amode(0) < 0) return(0);
+ inst |= am0 | a0reg;
+
+ if(!(amsktab[am0] & (C_ALTCTRL|M_APREDEC)))
+ return(error("invalid addressing mode"));
+
+ // If APREDEC, reverse register mask
+ if(am0 == APREDEC) {
+ w = rmask;
+ rmask = 0;
+ for(i = 0x8000; i; i >>= 1, w >>= 1)
+ rmask = (WORD)((rmask << 1) | w & 1);
+ }
+ } else { // ea,<rlist>
+ if(amode(0) < 0) return(0);
+ inst |= 0x0400 | am0 | a0reg;
+ if(*tok++ != ',') return(error("missing comma"));
+ if(*tok == EOL) return(error("missing register list"));
+
+ if(*tok == '#') { // ea,#<expr>
+ ++tok;
+ if(abs_expr(&eval) != OK) return(0);
+ if(eval >= 0x10000) return(error(range_error));
+ rmask = (WORD)eval;
+ } else
+ if(reglist(&rmask) < 0) return(0);
+
+ if(!(amsktab[am0] & (C_CTRL|M_APOSTINC)))
+ return(error("invalid addressing mode"));
+ }
+
+ D_word(inst);
+ D_word(rmask);
+ ea0gen(siz);
+
+ return(0);
+}
+
+//
+// --- CLR.x An ==> SUBA.x An,An -------------------------------------------------------------------
+//
+
+int m_clra(WORD inst, WORD siz) {
+ inst |= a0reg | reg_9[a0reg] | lwsiz_8[siz];
+ D_word(inst);
+
+ return(0);
+}
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// MACH.H - Code Generation
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __MACH_H__
+#define __MACH_H__
+
+#include "rmac.h"
+#include "amode.h"
+
+// Globals, Externals etc
+extern char *seg_error;
+extern char *undef_error;
+extern char *rel_error;
+extern char *range_error;
+extern char *abs_error;
+extern MNTAB machtab[];
+
+// Prototypes
+int m_unimp(), m_badmode(), m_bad6mode(), m_bad6inst();
+int m_self(WORD);
+int m_abcd(WORD, WORD);
+int m_reg(WORD, WORD);
+int m_imm(WORD, WORD);
+int m_imm8(WORD, WORD);
+int m_shi(WORD, WORD);
+int m_shr(WORD, WORD);
+int m_bitop(WORD, WORD);
+int m_exg(WORD, WORD);
+int m_ea(WORD, WORD);
+int m_br(WORD, WORD);
+int m_dbra(WORD, WORD);
+int m_link(WORD, WORD);
+int m_adda(WORD, WORD);
+int m_addq(WORD, WORD);
+int m_move(WORD, int);
+int m_moveq(WORD, WORD);
+int m_usp(WORD, WORD);
+int m_movep(WORD, WORD);
+int m_trap(WORD, WORD);
+int m_movem(WORD, WORD);
+int m_clra(WORD, WORD);
+
+#endif // __MACH_H__
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// MACRO.C - Macro Definition and Invocation
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "macro.h"
+#include "token.h"
+#include "error.h"
+#include "expr.h"
+#include "listing.h"
+#include "symbol.h"
+#include "procln.h"
+#include "direct.h"
+#include "debug.h"
+
+LONG curuniq; // Current macro's unique number
+TOKEN **argp; // Free spot in argptrs[]
+int macnum; // Unique number for macro definition
+
+static LONG macuniq; // Unique-per-macro number
+static SYM *curmac; // Macro currently being defined
+static char **curmln; // Previous macro line (or NULL)
+static VALUE argno; // Formal argument count
+
+static LONG *firstrpt; // First .rept line
+static LONG *nextrpt; // Last .rept line
+static int rptlevel; // .rept nesting level
+
+//
+// --- Initialize Macro Processor ------------------------------------------------------------------
+//
+
+void init_macro(void) {
+ macuniq = 0;
+ macnum = 1;
+ argp = NULL;
+ ib_macro();
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Exit from a Macro;
+// o pop any intervening include files and repeat blocks;
+// o restore argument stack;
+// o pop the macro.
+// -------------------------------------------------------------------------------------------------
+//
+
+int exitmac(void) {
+ IMACRO *imacro;
+ TOKEN **p;
+
+ // Pop intervening include files and .rept blocks
+ while(cur_inobj != NULL && cur_inobj->in_type != SRC_IMACRO)
+ fpop();
+
+ if(cur_inobj == NULL)
+ fatal("too many ENDMs");
+
+ // Restore
+ // o old arg context
+ // o old unique number
+ // ...and then pop the macro.
+
+ imacro = cur_inobj->inobj.imacro;
+ curuniq = imacro->im_olduniq;
+
+ p = --argp;
+ argp = (TOKEN **)*argp;
+
+ fpop();
+
+ mjump_align = 0;
+
+ return(0);
+}
+
+//
+// --- Add a Formal Argument to a Macro Definition -------------------------------------------------
+//
+
+int defmac2(char *argname) {
+ SYM *arg;
+
+ if(lookup(argname, MACARG, (int)curmac->sattr) != NULL)
+ return(error("multiple formal argument definition"));
+ arg = newsym(argname, MACARG, (int)curmac->sattr);
+ arg->svalue = argno++;
+
+ return(OK);
+}
+
+
+//
+// -------------------------------------------------------------------------------------------------
+// Add a line to a macro definition; also print lines to listing file (if enabled).
+// The last line of the macro (containing .endm) is not included in the macro. A label on that line
+// will be lost. `endflg' is misleading here. It is -1 for all lines but the last one (.endm),
+// when it is 0.
+// -------------------------------------------------------------------------------------------------
+//
+
+int defmac1(char *ln, int endflg) {
+ PTR p;
+ LONG len;
+
+ if(list_flag) {
+ listeol(); // Flush previous source line
+ lstout('.'); // Mark macro definition with period
+ }
+
+ if(endflg) {
+ len = strlen(ln) + 1 + sizeof(LONG);
+ p.cp = amem(len);
+ *p.lp = 0;
+ strcpy(p.cp + sizeof(LONG), ln);
+
+ // Link line of text onto end of list
+ if(curmln == NULL)
+ curmac->svalue = (VALUE)p.cp;
+ else
+ *curmln = p.cp;
+ curmln = (char **)p.cp;
+ return(1); // Keep looking
+ }
+ else
+ return(0); // Stop looking at the end
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Define macro
+//
+// macro foo arg1,arg2,...
+// :
+// :
+// endm
+//
+// Helper functions:
+// -----------------
+// `defmac1' adds lines of text to the macro definition
+// `defmac2' processes the formal arguments (and sticks them into the symbol table)
+// -------------------------------------------------------------------------------------------------
+//
+
+int defmac(void) {
+ char *p;
+ SYM *mac;
+
+ // Setup entry in symbol table, make sure the macro isn't a duplicate entry, and that
+ // it doesn't override any processor mnemonic or assembler directive.
+ if(*tok++ != SYMBOL) return(error("missing symbol"));
+ p = (char *)*tok++;
+ if(lookup(p, MACRO, 0) != NULL)
+ return(error("multiple macro definition"));
+
+ curmac = mac = newsym(p, MACRO, 0);
+ mac->svalue = 0;
+ mac->sattr = (WORD)(macnum++);
+
+ // Parse and define formal arguments in symbol table
+ if(*tok != EOL) {
+ argno = 0;
+ symlist(defmac2);
+ at_eol();
+ }
+
+ // Suck in the macro definition; we're looking for an ENDM symbol on a line
+ // by itself to terminate the definition.
+ curmln = NULL;
+ lncatch(defmac1, "endm ");
+
+ return(0);
+}
+
+//
+// --- Add lines to a .rept definition -------------------------------------------------------------
+//
+
+int defr1(char *ln, int kwno) {
+ LONG len;
+ LONG *p;
+
+ if(list_flag) {
+ listeol(); // Flush previous source line
+ lstout('#'); // Mark this a 'rept' block
+ }
+
+ switch(kwno) {
+ case 0: // .endr
+ if(--rptlevel == 0)
+ return(0);
+ goto addln;
+ case 1: // .rept
+ ++rptlevel;
+ default:
+
+ addln:
+
+ // Allocate length of line + 1('\0') + LONG
+ len = strlen(ln) + 1 + sizeof(LONG);
+ p = (LONG *)amem(len);
+ *p = 0;
+
+ strcpy((char*)(p + 1), ln);
+
+ if(nextrpt == NULL) {
+ firstrpt = p; // First line of rept statement
+ } else {
+ *nextrpt = (LONG)p;
+ }
+ nextrpt = p;
+
+ return(rptlevel);
+ }
+}
+
+//
+// --- Define a .rept block, this gets hairy because they can be nested ----------------------------
+//
+
+int defrept(void) {
+ INOBJ *inobj;
+ IREPT *irept;
+ VALUE eval;
+
+ // Evaluate repeat expression
+ if(abs_expr(&eval) != OK)
+ return(ERROR);
+
+ // Suck in lines for .rept block
+ firstrpt = NULL;
+ nextrpt = NULL;
+ rptlevel = 1;
+ lncatch(defr1, "endr rept ");
+
+ // Alloc and init input object
+ if(firstrpt) {
+ inobj = a_inobj(SRC_IREPT); // Create a new REPT input object
+ irept = inobj->inobj.irept;
+ irept->ir_firstln = firstrpt;
+ irept->ir_nextln = NULL;
+ irept->ir_count = eval;
+ }
+
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Hand off lines of text to the function `lnfunc' until a line containing one of the directives in
+// `dirlist' is encountered. Return the number of the keyword encountered (0..n)
+//
+// `dirlist' contains null-seperated terminated keywords. A final null terminates the list.
+// Directives are compared to the keywords without regard to case.
+//
+// If `lnfunc' is NULL, then lines are simply skipped.
+// If `lnfunc' returns an error, processing is stopped.
+//
+// `lnfunc' is called with an argument of -1 for every line but the last one, when it is called
+// with an argument of the keyword number that caused the match.
+// -------------------------------------------------------------------------------------------------
+//
+
+int lncatch(int (*lnfunc)(), char *dirlist) {
+ char *p;
+ int k;
+
+ if(lnfunc != NULL)
+ ++lnsave; // Tell tokenizer to keep lines
+
+ for(;;) {
+ if(tokln() == TKEOF) {
+ errors("encountered end-of-file looking for '%s'", dirlist);
+ fatal("cannot continue");
+ }
+
+ // Test for end condition. Two cases to handle:
+ // <directive>
+ // symbol: <directive>
+ p = NULL;
+ k = -1;
+
+ if(*tok == SYMBOL) {
+ if((tok[2] == ':' || tok[2] == DCOLON)) {
+ if(tok[3] == SYMBOL) // label: symbol
+ p = (char *)tok[4];
+ } else {
+ p = (char *)tok[1]; // symbol
+ }
+ }
+
+ if(p != NULL) {
+ if(*p == '.') // ignore leading '.'s
+ ++p;
+ k = kwmatch(p, dirlist);
+ }
+
+ // Hand-off line to function
+ // if it returns 0, and we found a keyword, stop looking.
+ // if it returns 1, hand off the line and keep looking.
+ if(lnfunc != NULL)
+ k = (*lnfunc)(lnbuf, k);
+
+ if(!k)
+ break;
+ }
+
+ if(lnfunc != NULL)
+ --lnsave; // Tell tokenizer to stop keeping lines
+
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// See if the string `kw' matches one of the keywords in `kwlist'. If so, return the number of
+// the keyword matched. Return -1 if there was no match.
+// Strings are compared without regard for case.
+// -------------------------------------------------------------------------------------------------
+//
+
+int kwmatch(char *kw, char *kwlist) {
+ char *p;
+ char c1;
+ char c2;
+ int k;
+
+ for(k = 0; *kwlist; ++k) {
+ for(p = kw;;) {
+ c1 = *kwlist++;
+ c2 = *p++;
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 += 32;
+
+ if(c1 == ' ' && c2 == EOS)
+ return(k);
+
+ if(c1 != c2)
+ break;
+ }
+
+ // Skip to beginning of next keyword in `kwlist'
+ while(*kwlist && *kwlist != ' ')
+ ++kwlist;
+ if(*kwlist== ' ')
+ ++kwlist;
+ }
+
+ return(-1);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Invoke a macro
+// o parse, count and copy arguments
+// o push macro's string-stream
+// -------------------------------------------------------------------------------------------------
+//
+
+int invokemac(SYM *mac, WORD siz) {
+ TOKEN *p = NULL;
+ IMACRO *imacro;
+ INOBJ *inobj;
+ int dry_run;
+ WORD nargs;
+ WORD arg_siz = 0;
+ TOKEN **argptr = NULL;
+ TOKEN *beg_tok;
+
+ if((!strcmp(mac->sname, "mjump") || !strcmp(mac->sname, "mpad")) && !in_main) {
+ error("macro cannot be used outside of .gpumain");
+ return(ERROR);
+ }
+
+ inobj = a_inobj(SRC_IMACRO); // Alloc and init IMACRO
+ imacro = inobj->inobj.imacro;
+ imacro->im_siz = siz;
+ nargs = 0;
+ beg_tok = tok;
+
+ for(dry_run = 1;; --dry_run) {
+ for(tok = beg_tok; *tok != EOL;) {
+ if(dry_run) ++nargs;
+ else *argptr++ = p;
+
+ while(*tok != ',' && *tok != EOL) {
+ if(*tok == '\\' && tok[1] != EOL) ++tok;
+ switch((int)*tok) {
+ case CONST:
+ case SYMBOL:
+ case ACONST:
+ if(dry_run) arg_siz += sizeof(TOKEN), ++tok;
+ else *p++ = *tok++;
+ // FALLTHROUGH
+ default:
+ if(dry_run) arg_siz += sizeof(TOKEN), ++tok;
+ else *p++ = *tok++;
+ break;
+ }
+ }
+
+ if(dry_run) arg_siz += sizeof(TOKEN);
+ else *p++ = EOL;
+
+ if(*tok == ',') ++tok;
+ }
+
+ // Allocate space for argument ptrs and so on and then go back and construct the arg frame
+ if(dry_run) {
+ if(nargs != 0) p = (TOKEN *)malloc((LONG)(arg_siz + 1));
+ argptr = (TOKEN **)malloc((LONG)((nargs + 1) * sizeof(LONG)));
+ *argptr++ = (TOKEN *)argp;
+ argp = argptr;
+ } else
+ break;
+ }
+
+
+ // Setup imacro:
+ // o #arguments;
+ // o -> macro symbol;
+ // o -> macro definition string list;
+ // o save 'curuniq', to be restored when the macro pops;
+ // o bump `macuniq' counter and set 'curuniq' to it;
+ imacro->im_nargs = nargs;
+ imacro->im_macro = mac;
+ imacro->im_nextln = (LONG *)mac->svalue;
+ imacro->im_olduniq = curuniq;
+ curuniq = ++macuniq;
+
+ DEBUG {
+ printf("nargs=%d\n", nargs);
+ for(nargs = 0; nargs < imacro->im_nargs; ++nargs) {
+ printf("arg%d=", nargs);
+ dumptok(argp[imacro->im_nargs - nargs - 1]);
+ }
+ }
+
+ return(OK);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Setup inbuilt macros
+// -------------------------------------------------------------------------------------------------
+//
+
+void ib_macro(void) {
+ SYM *mac;
+
+ curmac = mac = newsym("mjump", MACRO, 0);
+ mac->svalue = 0;
+ mac->sattr = (WORD)(macnum++);
+ argno = 0;
+ defmac2("cc");
+ defmac2("addr");
+ defmac2("jreg");
+ curmln = NULL;
+ defmac1(" nop", -1);
+ defmac1(" movei #\\addr,\\jreg", -1);
+ defmac1(" jump \\cc,(\\jreg)", -1);
+ defmac1(" nop", -1);
+ defmac1(" nop", -1);
+
+ curmac = mac = newsym("mjr", MACRO, 0);
+ mac->svalue = 0;
+ mac->sattr = (WORD)(macnum++);
+ argno = 0;
+ defmac2("cc");
+ defmac2("addr");
+ curmln = NULL;
+ defmac1(" jr \\cc,\\addr", -1);
+ defmac1(" nop", -1);
+ defmac1(" nop", -1);
+
+ curmac = mac = newsym("mpad", MACRO, 0);
+ mac->svalue = 0;
+ mac->sattr = (WORD)(macnum++);
+ argno = 0;
+ defmac2("size");
+ curmln = NULL;
+ defmac1(" .rept (\\size/2)", -1);
+ defmac1(" nop", -1);
+ defmac1(" .endr", -1);
+}
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// MACRO.H - Macro Definition and Invocation
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __MACRO_H__
+#define __MACRO_H__
+
+#include "rmac.h"
+
+// Globals, externals etc
+extern LONG curuniq;
+extern TOKEN **argp;
+extern int mjump_align;
+
+// Prototypes
+void init_macro(void);
+int exitmac(void);
+int defmac(void);
+int defrept(void);
+int lncatch(int (*)(), char *);
+int kwmatch(char *, char *);
+int invokemac(SYM *, WORD);
+void ib_macro(void);
+
+#endif // __MACRO_H__
+
--- /dev/null
+#
+# RMAC - Reboot's Macro Assembler for the Atari Jaguar
+# Copyright (C) 199x Landon Dyer, 2011 Reboot & Friends
+# MAKEFILE for Non-Windows Compilation
+# Currently tested against Cygwin under Windows XP Pro
+#
+
+rm = /bin/rm -f
+CC = cc
+
+CFLAGS = -g -D__GCCUNIX__ -I.
+
+SRCS = amode.c debug.c direct.c eagen.c error.c expr.c listing.c mach.c macro.c mark.c object.c procln.c risca.c rmac.c sect.c symbol.c token.c
+
+OBJS = amode.o debug.o direct.o eagen.o error.o expr.o listing.o mach.o macro.o mark.o object.o procln.o risca.o rmac.o sect.o symbol.o token.o
+
+#
+# Build everything
+#
+
+all : mntab.h 68ktab.h kwtab.h risckw.h rmac
+
+#
+# Generated Sources for State Machines and Keyword, Directive and Mnemonic Definitions
+#
+
+mntab.h : mntab 68kmn kwgen
+ cat mntab 68kmn | ./kwgen mn >mntab.h
+
+68ktab.h 68kmn : 68ktab 68ktab 68kgen
+ ./68kgen 68kmn <68ktab >68ktab.h
+
+kwtab.h : kwtab kwgen
+ ./kwgen kw <kwtab >kwtab.h
+
+risckw.h : kwtab kwgen
+ ./kwgen mr <risctab >risckw.h
+
+#
+# Build Tools
+#
+
+kwgen.o : kwgen.c
+ $(CC) $(CFLAGS) -c kwgen.c
+
+kwgen : kwgen.o
+ $(CC) $(CFLAGS) -o kwgen kwgen.o
+
+68kgen.o : 68kgen.c
+ $(CC) $(CFLAGS) -c 68kgen.c
+
+68kgen : 68kgen.o
+ $(CC) $(CFLAGS) -o 68kgen 68kgen.o
+
+#
+# Build RMAC Executable
+#
+
+amode.o : amode.c
+ $(CC) $(CFLAGS) -c amode.c
+
+debug.o : debug.c
+ $(CC) $(CFLAGS) -c debug.c
+
+direct.o : direct.c
+ $(CC) $(CFLAGS) -c direct.c
+
+eagen.o : eagen.c
+ $(CC) $(CFLAGS) -c eagen.c
+
+error.o : error.c
+ $(CC) $(CFLAGS) -c error.c
+
+expr.o : expr.c
+ $(CC) $(CFLAGS) -c expr.c
+
+listing.o : listing.c
+ $(CC) $(CFLAGS) -c listing.c
+
+mach.o : mach.c
+ $(CC) $(CFLAGS) -c mach.c
+
+macro.o : macro.c
+ $(CC) $(CFLAGS) -c macro.c
+
+mark.o : mark.c
+ $(CC) $(CFLAGS) -c mark.c
+
+object.o : object.c
+ $(CC) $(CFLAGS) -c object.c
+
+procln.o : procln.c
+ $(CC) $(CFLAGS) -c procln.c
+
+risca.o : risca.c
+ $(CC) $(CFLAGS) -c risca.c
+
+rmac.o : rmac.c
+ $(CC) $(CFLAGS) -c rmac.c
+
+sect.o : sect.c
+ $(CC) $(CFLAGS) -c sect.c
+
+symbol.o : symbol.c
+ $(CC) $(CFLAGS) -c symbol.c
+
+token.o : token.c
+ $(CC) $(CFLAGS) -c token.c
+
+rmac : $(OBJS)
+ $(CC) $(CFLAGS) -o rmac $(OBJS)
+
+#
+# Clean Build Environment
+#
+
+clean:
+ $(rm) $(OBJS) kwgen.o 68kgen.o rmac kwgen 68kgen kwtab.h 68ktab.h mntab.h risckw.h
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// MARK.C - A record of things that are defined relative to any of the sections
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "mark.h"
+#include "error.h"
+#include "object.h"
+#include "risca.h"
+
+MCHUNK *firstmch; // First mark chunk
+MCHUNK *curmch; // Current mark chunk
+PTR markptr; // Deposit point in current mark chunk
+LONG mcalloc; // #bytes alloc'd to current mark chunk
+LONG mcused; // #bytes used in current mark chunk
+WORD curfrom; // Current "from" section
+
+//
+// --- Initialize Marker ---------------------------------------------------------------------------
+//
+
+void init_mark(void) {
+ firstmch = curmch = NULL;
+ mcalloc = mcused = 0;
+ curfrom = 0;
+}
+
+//
+// --- Wrap up marker (called after final mark is made) --------------------------------------------
+//
+
+void stopmark(void) {
+ if(curmch) {
+ *markptr.wp = MCHEND; // Mark end of block
+ curmch->mcused = mcused; // Update #used in mark block
+ }
+}
+
+//
+// --- Mark a word or longword relocatable ---------------------------------------------------------
+//
+
+int rmark(int from, LONG loc, int to, int size, SYM *symbol) {
+ WORD w;
+
+ if((mcalloc - mcused) < MIN_MARK_MEM)
+ amark();
+
+ w = (WORD)(size | to);
+ if(from != curfrom)
+ w |= MCHFROM;
+ if(symbol != NULL)
+ w |= MSYMBOL;
+
+ mcused += sizeof(WORD) + sizeof(LONG);
+ *markptr.wp++ = w;
+ *markptr.lp++ = loc;
+
+ if(w & MCHFROM) {
+ *markptr.wp++ = (WORD)from;
+ curfrom = (WORD)from;
+ mcused += sizeof(WORD);
+ }
+
+ if(w & MSYMBOL) {
+ *markptr.sy++ = symbol;
+ mcused += sizeof(LONG);
+ }
+
+ *markptr.wp = 0x0000;
+
+ return(0);
+}
+
+//
+// --- Allocate another chunk of mark space --------------------------------------------------------
+//
+
+int amark(void) {
+ MCHUNK *p;
+
+ // Alloc mark block header (and data) and set it up.
+ p = (MCHUNK *)amem((long)(sizeof(MCHUNK)) + MARK_ALLOC_INCR);
+ p->mcnext = NULL;
+ p->mcalloc = MARK_ALLOC_INCR;
+ p->mcptr.cp = (char *)(((char *)p) + sizeof(MCHUNK));
+
+ if(curmch) { // Link onto previous chunk
+ *markptr.wp++ = MCHEND; // Mark end of block
+ curmch->mcused = mcused;
+ curmch->mcnext = p;
+ }
+ if(!firstmch)
+ firstmch = p;
+
+ curmch = p; // Setup global vars
+ markptr = p->mcptr;
+ mcalloc = MARK_ALLOC_INCR;
+ mcused = 0;
+
+ return(0);
+}
+
+//
+// --- Make mark image for BSD .o file -------------------------------------------------------------
+//
+
+LONG bsdmarkimg(char *mp, LONG siz, LONG tsize, int reqseg) {
+ MCHUNK *mch; // Mark chunk
+ PTR p; // Source point from within mark chunk
+ WORD from; // Section fixups are currently FROM
+ WORD w; // A word (temp)
+ LONG loc; // Location (temp)
+ SYM *symbol; // Symbols (temp)
+ char *wp; // Pointer into raw relocation info
+ char *dp; // Deposit point for RELMOD info
+ LONG diff; // Difference to relocate (RELMOD)
+ LONG raddr, rflag = 0; // BSD relocation address and flags
+ LONG rsize; // Relocation size
+ int validsegment = 0; // Valid segment being processed
+
+ rsize = 0; // Initialise relocation size
+ chptr = mp;
+
+ from = 0;
+ for(mch = firstmch; mch != NULL; mch = mch->mcnext)
+ for(p = mch->mcptr;;) {
+ w = *p.wp++; // Next mark entry
+
+ if(w & MCHEND) break; // End of mark chunk
+
+ // Get mark record
+ symbol = NULL;
+ loc = *p.lp++; // Mark location
+ if(w & MCHFROM) { // Maybe change "from" section
+ from = *p.wp++;
+ if(obj_format == BSD) {
+ if(reqseg == TEXT) { // Requested segment is TEXT
+ if(from == TEXT) validsegment = 1;
+ else validsegment = 0;
+ } else { // Requested segment is DATA
+ if(from == DATA) validsegment = 1;
+ else validsegment = 0;
+ }
+ }
+ }
+
+ if(w & MSYMBOL) // Maybe includes a symbol
+ symbol = *p.sy++;
+
+ if(obj_format == BSD) {
+ raddr = loc; // Set relocation address
+ if(validsegment)
+ D_long(raddr); // Write relocation address
+ if(w & MPCREL)
+ rflag = 0x000000A0; // PC-relative fixup
+ else
+ rflag = 0x00000040; // Absolute fixup
+ if(w & MMOVEI)
+ rflag |= 0x00000001;
+ }
+
+ // Compute mark position in relocation information;
+ // in RELMOD mode, get address of data to fix up.
+ if(from == DATA)
+ loc += tsize;
+ wp = (char *)(mp + loc);
+
+ if(symbol) {
+ // Deposit external reference
+ if(obj_format == BSD) {
+ rflag |= 0x00000010; // Set external reloc flag bit
+ rflag |= (symbol->senv << 8); // Put symbol index in flags
+ if(symbol->sattre & RISCSYM) rflag |= 0x00000001;
+ if(validsegment) {
+ D_long(rflag); // Write relocation flags
+ rsize += 8; // Increment relocation size
+ }
+ }
+
+ } else {
+
+ if(obj_format == BSD) {
+ w &= TDB; // Set reloc flags to segment
+ switch(w) {
+ case TEXT: rflag |= 0x00000400; break;
+ case DATA: rflag |= 0x00000600; break;
+ case BSS: rflag |= 0x00000800; break;
+ }
+ if(validsegment) {
+ D_long(rflag); // Write relocation flags
+ rsize += 8; // Increment relocation size
+ }
+ w &= TDB;
+ if(validsegment) {
+ if(w & (DATA|BSS)) {
+ dp = objimage + BSDHDRSIZE + loc;
+ diff = ((LONG)(*dp++ & 0xff)) << 24;
+ diff |= ((LONG)(*dp++ & 0xff)) << 16;
+ diff |= ((LONG)(*dp++ & 0xff)) << 8;
+ diff |= (LONG)(*dp & 0xff);
+ DEBUG printf("diff=%lx ==> ", diff);
+ if(rflag & 0x01)
+ diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
+ diff += sect[TEXT].sloc;
+ if(w == BSS)
+ diff += sect[DATA].sloc;
+ if(rflag & 0x01)
+ diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
+ dp = objimage + BSDHDRSIZE + loc;
+ *dp++ = (char)(diff >> 24);
+ *dp++ = (char)(diff >> 16);
+ *dp++ = (char)(diff >> 8);
+ *dp = (char)diff;
+ DEBUG printf("%lx\n", diff);
+ }
+ }
+ }
+ }
+ }
+
+ if(obj_format == BSD) // Return relocation size
+ return(rsize);
+ else
+ return(siz);
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// MARK.H - A record of things that are defined relative to any of the sections
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __MARK_H__
+#define __MARK_H__
+
+#include "rmac.h"
+#include "sect.h"
+
+#define MARK_ALLOC_INCR 1024 // #bytes to alloc for more mark space
+#define MIN_MARK_MEM (3*sizeof(WORD)+2*sizeof(LONG))
+
+// Globals, Externals etc
+extern MCHUNK *firstmch;
+
+// Prototypes
+void init_mark(void);
+void stopmark(void);
+int rmark(int, LONG, int, int, SYM *);
+int amark(void);
+LONG bsdmarkimg(char *, LONG, LONG, int);
+
+#endif // __MARK_H__
\ No newline at end of file
--- /dev/null
+.org 0
+org 0
+.even 1
+even 1
+.68000 3
+.bss 4
+bss 4
+.data 5
+data 5
+.text 6
+text 6
+.offset 7
+offset 7
+.comm 8
+comm 8
+.init 9
+init 9
+.cargs 10
+cargs 10
+.goto 11
+goto 11
+.dc 12
+dc 12
+.ds 13
+ds 13
+.undefmac 14
+undefmac 14
+.macundef 14
+macundef 14
+.gpu 15
+.dsp 16
+.dcb 17
+dcb 17
+.equ 18
+equ 18
+.dump 20
+dump 20
+.incbin 21
+incbin 21
+.disable 22
+disable 22
+.enable 23
+enable 23
+.extern 24
+.globl 24
+extern 24
+globl 24
+.regbank0 25
+.regbank1 26
+.assert 28
+assert 28
+.include 33
+include 33
+.end 34
+end 34
+.list 38
+list 38
+.nlist 39
+nlist 39
+.nolist 39
+nolist 39
+.long 40
+long 40
+.phrase 41
+phrase 41
+.dphrase 42
+dphrase 42
+.qphrase 43
+qphrase 43
+.title 44
+title 44
+.subttl 45
+subttl 45
+.eject 46
+eject 46
+.error 47
+error 47
+.warn 48
+warn 48
+.noclear 49
+noclear 49
+.equrundef 50
+equrundef 50
+.regundef 50
+regundef 50
+.ccundef 51
+ccundef 51
+.print 52
+print 52
+.gpumain 53
+.jpad 54
+jpad 54
+.nojpad 55
+nojpad 55
+.fail 56
+fail 56
+.if 500
+if 500
+.else 501
+else 501
+.endif 502
+endif 502
+.iif 503
+iif 503
+.macro 504
+macro 504
+.endm 505
+endm 505
+.rept 506
+rept 506
+.endr 507
+endr 507
+.exitm 510
+exitm 510
+abcd 1001
+add 1003
+adda 1005
+addi 1006
+addq 1007
+addx 1008
+and 1010
+andi 1012
+asl 1015
+asr 1019
+bcc 1023
+bhs 1023
+bcs 1024
+blo 1024
+beq 1025
+bz 1025
+bze 1025
+bge 1026
+bgt 1027
+bhi 1028
+ble 1029
+bls 1030
+blt 1031
+bmi 1032
+bne 1033
+bnz 1033
+bpl 1034
+bvc 1035
+bvs 1036
+bchg 1037
+bclr 1041
+bra 1045
+bt 1045
+bset 1046
+bsr 1050
+btst 1051
+chk 1055
+clr 1056
+cmp 1058
+cmpa 1060
+cmpi 1061
+cmpm 1062
+dbcc 1063
+dbcs 1064
+dblo 1064
+dbeq 1065
+dbze 1065
+dbf 1066
+dbra 1066
+dbge 1067
+dbgt 1068
+dbhi 1069
+dbhs 1069
+dble 1070
+dbls 1071
+dblt 1072
+dbmi 1073
+dbne 1074
+dbnz 1074
+dbpl 1075
+dbt 1076
+dbvc 1077
+dbvs 1078
+divs 1079
+divu 1080
+eor 1081
+eori 1082
+exg 1085
+ext 1086
+illegal 1088
+jmp 1089
+jsr 1090
+lea 1091
+link 1092
+lsl 1093
+lsr 1097
+move 1101
+movea 1108
+movem 1109
+movep 1110
+moveq 1112
+muls 1113
+mulu 1114
+nbcd 1115
+neg 1116
+negx 1117
+nop 1118
+not 1119
+or 1120
+ori 1122
+pea 1125
+reset 1126
+rol 1127
+ror 1131
+roxl 1135
+roxr 1139
+rte 1143
+rtr 1144
+rts 1145
+sbcd 1146
+scc 1148
+shs 1148
+scs 1149
+slo 1149
+seq 1150
+sze 1150
+sf 1151
+sge 1152
+sgt 1153
+shi 1154
+sle 1155
+sls 1156
+slt 1157
+smi 1158
+sne 1159
+snz 1159
+spl 1160
+st 1161
+svc 1162
+svs 1163
+stop 1164
+sub 1165
+suba 1167
+subi 1168
+subq 1169
+subx 1170
+swap 1172
+tas 1173
+trap 1174
+trapv 1175
+tst 1176
+unlk 1177
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// OBJECT.C - Writing Object Files
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "object.h"
+#include "sect.h"
+#include "symbol.h"
+#include "mark.h"
+#include "error.h"
+#include "risca.h"
+
+LONG symsize = 0; // Size of BSD symbol table
+LONG strindx = 0x00000004; // BSD string table index
+char *strtable; // Pointer to the symbol string table
+char *objimage; // Global object image pointer
+
+//
+// --- Add an entry to the BSD symbol table --------------------------------------------------------
+//
+
+char *constr_bsdsymtab(char *buf, SYM *sym, int globflag) {
+ LONG z; // Scratch long
+ WORD w1; // Scratch word
+ int w2; // Scratch long
+
+ chptr = buf; // Point to buffer for deposit longs
+ D_long(strindx); // Deposit the symbol string index
+
+ w1 = sym->sattr; // Obtain symbol attribute
+ w2 = sym->sattre;
+ z = 0; // Initialise resulting symbol flags
+ if(w1 & EQUATED) {
+ z = 0x02000000; // Set equated flag
+ } else {
+ switch(w1 & TDB) {
+ case TEXT: z = 0x04000000; break; // Set TEXT segment flag
+ case DATA: z = 0x06000000; break; // Set DATA segment flag
+ case BSS : z = 0x08000000; break; // Set BSS segment flag
+ }
+ }
+ if(globflag) z |= 0x01000000; // Set global flag if requested
+ D_long(z); // Deposit symbol attribute
+
+ z = sym->svalue; // Obtain symbol value
+ w1 &= DATA|BSS; // Determine DATA or BSS flag
+ if(w1)
+ z += sect[TEXT].sloc; // If DATA or BSS add TEXT segment size
+ if(w1 & BSS)
+ z += sect[DATA].sloc; // If BSS add DATA segment size
+ D_long(z); // Deposit symbol value
+
+ strcpy(strtable + strindx, sym->sname);
+
+ strindx += strlen(sym->sname) + 1; // Incr string index incl null terminate
+ buf += 12; // Increment buffer to next record
+ symsize += 12; // Increment symbol table size
+
+ return(buf);
+}
+
+//
+// --- Generate object file ------------------------------------------------------------------------
+//
+
+int object(WORD fd) {
+ LONG t; // Scratch long
+ LONG tds; // TEXT & DATA segment size
+ int i; // Temporary int
+ CHUNK *cp; // Chunk (for gather)
+ char *buf; // Scratch area
+ char *p; // Temporary ptr
+ LONG ssize; // Size of symbols
+ LONG trsize, drsize; // Size of relocations
+
+ // Write requested object file...
+ switch(obj_format) {
+ case BSD:
+ ssize = ((LONG)sy_assign(NULL, NULL)); // Assign index numbers to the symbols
+ tds = sect[TEXT].sloc + sect[DATA].sloc; // Get size of TEXT and DATA segment
+ buf = malloc(0x400000); // Allocate 4mb object file image memory
+ if(buf == NULL) {
+ error("cannot allocate object file memory (in BSD mode)");
+ return(ERROR);
+ }
+ memset(buf, 0, 0x400000); // Reset allocated memory
+ objimage = buf; // Set global object image pointer
+ strtable = malloc(0x200000); // Allocate 2mb scratch buffer
+ if(strtable == NULL) {
+ error("cannot allocate string table memory (in BSD mode)");
+ return(ERROR);
+ }
+ memset(strtable, 0, 0x200000); // Reset allocated memory
+
+ // Build object file header
+ chptr = buf; // Base of header
+ t = 0x00000107;
+ D_long(t); // Magic number
+ t = sect[TEXT].sloc; // TEXT size
+ D_long(t);
+ t = sect[DATA].sloc; // DATA size
+ D_long(t);
+ t = sect[BSS].sloc; // BSS size
+ D_long(t);
+ t = 0x00000000;
+ D_long(t); // Symbol size
+ D_long(t); // First entry (0L)
+ D_long(t); // TEXT relocation size
+ D_long(t); // BSD relocation size
+
+ // Construct TEXT and DATA segments (without relocation changes)
+ p = buf + BSDHDRSIZE;
+ for(i = TEXT; i <= DATA; ++i)
+ for(cp = sect[i].sfcode; cp != NULL; cp = cp->chnext) {
+ copy(p, cp->chptr, cp->ch_size);
+ p += cp->ch_size;
+ }
+
+ // Do relocation tables (and make changes to segment data)
+ p = buf + (BSDHDRSIZE + tds); // Move obj image ptr to reloc info
+ trsize = bsdmarkimg(p, tds, sect[TEXT].sloc, TEXT);// Do TEXT relocation table
+ chptr = buf + 24; // Point to relocation hdr entry
+ D_long(trsize); // Write the relocation table size
+ p = buf + (BSDHDRSIZE + tds + trsize); // Move obj image ptr to reloc info
+ drsize = bsdmarkimg(p, tds, sect[TEXT].sloc, DATA);// Do DATA relocation table
+ chptr = buf + 28; // Point to relocation hdr entry
+ D_long(drsize); // Write the relocation table size
+
+ p = buf + (BSDHDRSIZE + tds + trsize + drsize); // Point to start of symbol table
+ sy_assign(p, constr_bsdsymtab); // Build symbol and string tables
+ chptr = buf + 16; // Point to sym table size hdr entry
+ D_long(symsize); // Write the symbol table size
+
+ // Point to string table
+ p = buf + (BSDHDRSIZE + tds + trsize + drsize + symsize);
+
+ memcpy(p, strtable, strindx); // Copy string table to object image
+ if(buf) free(strtable); // Free allocated memory
+ chptr = p; // Point to string table size long
+ D_long(strindx); // Write string table size
+
+ // Write the BSD object file from the object image buffer
+ write(fd, buf, BSDHDRSIZE + tds + trsize + drsize + symsize + strindx + 4);
+
+ if(buf) free(buf); // Free allocated memory
+ break;
+ }
+
+ return(0);
+}
+
+
+
+
+
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// OBJECT.H - Writing Object Files
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __OBJECT_H__
+#define __OBJECT_H__
+
+#include "rmac.h"
+
+#define BSDHDRSIZE 0x20 // Size of BSD header
+
+// Globals, externals etc
+extern char *objimage;
+
+// Prototypes
+int object(WORD);
+
+#endif // __OBJECT_H__
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// PARMODE.C - Addressing Modes Parser Include
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+// This file is included (twice) to parse two addressing modes, into slightly different var names
+{
+ // Dn
+ // An
+ // # expression
+ if((*tok >= KW_D0) && (*tok <= KW_D7)) {
+ AMn = DREG;
+ AnREG = *tok++ & 7;
+ } else if((*tok >= KW_A0) && (*tok <= KW_A7)) {
+ AMn = AREG;
+ AnREG = *tok++ & 7;
+ } else if(*tok == '#') {
+ ++tok;
+ if(expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
+ return(ERROR);
+ AMn = IMMED;
+ }
+ // (An)
+ // (An)+
+ // (An,Xn[.siz][*scale])
+ // (PC,Xn[.siz][*scale])
+ // (d16,An)
+ // (d8,An,Xn[.siz][*scale])
+ // (d16,PC)
+ // (d8,PC,Xn[.siz][*scale])
+ // ([bd,An],Xn,od)
+ // ([bd,An,Xn],od)
+ // ([bd,PC],Xn,od)
+ // ([bd,PC,Xn],od)
+ else if(*tok == '(') {
+ ++tok;
+ if((*tok >= KW_A0) && (*tok <= KW_A7)) {
+ AnREG = *tok++ & 7;
+ if(*tok == ')') {
+ ++tok;
+ if(*tok == '+') {
+ ++tok;
+ AMn = APOSTINC;
+ } else AMn = AIND;
+ goto AnOK;
+ }
+ AMn = AINDEXED;
+ goto AMn_IX0; // Handle ",Xn[.siz][*scale])"
+ } else if(*tok == KW_PC) { // (PC,Xn[.siz][*scale])
+ ++tok;
+ AMn = PCINDEXED;
+
+ // Common index handler; enter here with `tok' pointing at the comma.
+
+ AMn_IX0: // Handle indexed with missing expr
+
+ AnEXVAL = 0;
+ AnEXATTR = ABS | DEFINED;
+
+ AMn_IXN: // Handle any indexed (tok -> a comma)
+
+ if(*tok++ != ',')
+ goto badmode;
+ if(*tok < KW_D0 || *tok > KW_A7)
+ goto badmode;
+ AnIXREG = *tok++ & 15;
+
+ switch((int)*tok) { // Index reg size: <empty> | .W | .L
+ case DOTW:
+ ++tok;
+ default:
+ AnIXSIZ = 0;
+ break;
+ case DOTL:
+ AnIXSIZ = 0x0800;
+ ++tok;
+ break;
+ case DOTB: // .B not allowed here...
+ goto badmode;
+ }
+
+ if(*tok == '*') { // scale: *1, *2, *4, *8
+ ++tok;
+ if(*tok++ != CONST || *tok > 8)
+ goto badmode;
+
+ switch((int)*tok++) {
+ case 1:
+ break;
+ case 2:
+ AnIXSIZ |= TIMES2;
+ break;
+ case 4:
+ AnIXSIZ |= TIMES4;
+ break;
+ case 8:
+ AnIXSIZ |= TIMES8;
+ break;
+ default:
+ goto badmode;
+ }
+ }
+
+ if(*tok++ != ')') // final ")"
+ goto badmode;
+ goto AnOK;
+ } else if(*tok == '[') { // ([...
+ goto unmode;
+ } else { // (expr...
+ if(expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
+ return ERROR;
+ if(*tok++ != ',')
+ goto badmode;
+
+ if((*tok >= KW_A0) && (*tok <= KW_A7)) {
+ AnREG = *tok & 7;
+ ++tok;
+ if(*tok == ',') {
+ AMn = AINDEXED;
+ goto AMn_IXN;
+ } else if(*tok == ')') {
+ AMn = ADISP;
+ ++tok;
+ goto AnOK;
+ } else goto badmode;
+ } else if(*tok == KW_PC) {
+ if(*++tok == ',') { // expr(PC,Xn...)
+ AMn = PCINDEXED;
+ goto AMn_IXN;
+ } else if(*tok == ')') {
+ AMn = PCDISP; // expr(PC)
+ ++tok;
+ goto AnOK;
+ } else goto badmode;
+ } else goto badmode;
+ }
+ } else if(*tok=='-' && tok[1]=='(' && ((tok[2]>=KW_A0) && (tok[2]<=KW_A7)) && tok[3]==')') {
+ AMn = APREDEC;
+ AnREG = tok[2] & 7;
+ tok += 4;
+ } else if(*tok == KW_CCR) {
+ AMn = AM_CCR;
+ ++tok;
+ goto AnOK;
+ } else if(*tok == KW_SR) {
+ AMn = AM_SR;
+ ++tok;
+ goto AnOK;
+ } else if(*tok == KW_USP) {
+ AMn = AM_USP;
+ ++tok;
+ goto AnOK;
+ }
+ // expr
+ // expr.w
+ // expr.l
+ // d16(An)
+ // d8(An,Xn[.siz])
+ // d16(PC)
+ // d8(PC,Xn[.siz])
+ else {
+ if(expr(AnEXPR, &AnEXVAL, &AnEXATTR, &AnESYM) != OK)
+ return ERROR;
+
+ if(*tok == DOTW) { // expr.W
+ ++tok;
+ AMn = ABSW;
+ goto AnOK;
+ } else if(*tok != '(') { // expr[.L]
+ AMn = ABSL;
+ // Defined, absolute values from $FFFF8000..$00007FFF get optimized to absolute short
+ if((AnEXATTR & (TDB|DEFINED)) == DEFINED && (AnEXVAL + 0x8000) < 0x10000)
+ AMn = ABSW;
+
+ if(*tok == DOTL) { // force .L
+ ++tok;
+ AMn = ABSL;
+ }
+ goto AnOK;
+ }
+
+ ++tok;
+ if((*tok >= KW_A0) && (*tok <= KW_A7)) {
+ AnREG = *tok++ & 7;
+ if(*tok == ')') {
+ AMn = ADISP;
+ ++tok;
+ goto AnOK;
+ }
+ AMn = AINDEXED;
+ goto AMn_IXN;
+ } else if(*tok == KW_PC) {
+ if(*++tok == ')') {
+ AMn = PCDISP;
+ ++tok;
+ goto AnOK;
+ }
+ AMn = PCINDEXED;
+ goto AMn_IXN;
+ }
+ goto badmode;
+ }
+
+ // Addressing mode OK
+
+ AnOK:
+ ;
+}
+
+// Cleanup dirty little macros
+#undef AnOK
+#undef AMn
+#undef AnREG
+#undef AnIXREG
+#undef AnIXSIZ
+#undef AnEXPR
+#undef AnEXVAL
+#undef AnEXATTR
+#undef AnOEXPR
+#undef AnOEXVAL
+#undef AnOEXATTR
+#undef AnESYM
+#undef AMn_IX0
+#undef AMn_IXN
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// PROCLN.C - Line Processing
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "procln.h"
+#include "listing.h"
+#include "amode.h"
+#include "error.h"
+#include "sect.h"
+#include "expr.h"
+#include "mach.h"
+#include "direct.h"
+#include "macro.h"
+#include "symbol.h"
+#include "risca.h"
+
+#define DEF_KW // Declare keyword values
+#include "kwtab.h" // Incl generated keyword tables & defs
+
+#define DEF_MN // Incl 68k keyword definitions
+#define DECL_MN // Incl 68k keyword state machine tables
+#include "mntab.h"
+
+#define DEF_MR
+#define DECL_MR
+#include "risckw.h"
+
+IFENT *ifent; // Current ifent
+static IFENT ifent0; // Root ifent
+static IFENT *f_ifent; // Freelist of ifents
+static int disabled; // Assembly conditionally disabled
+int just_bss; // 1, ds.b in microprocessor mode
+VALUE pcloc; // Value of "PC" at beginning of line
+IFENT *ifent; // Current ifent
+SYM *lab_sym; // Label on line (or NULL)
+
+
+char extra_stuff[] = "extra (unexpected) text found after addressing mode";
+char *comma_error = "missing comma";
+char *syntax_error = "syntax error";
+char *locgl_error = "cannot GLOBL local symbol";
+char *lab_ignored = "label ignored";
+
+// Table to convert an addressing-mode number to a bitmask.
+LONG amsktab[0112] = {
+ M_DREG, M_DREG, M_DREG, M_DREG,
+ M_DREG, M_DREG, M_DREG, M_DREG,
+
+ M_AREG, M_AREG, M_AREG, M_AREG,
+ M_AREG, M_AREG, M_AREG, M_AREG,
+
+ M_AIND, M_AIND, M_AIND, M_AIND,
+ M_AIND, M_AIND, M_AIND, M_AIND,
+
+ M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
+ M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
+
+ M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
+ M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
+
+ M_ADISP, M_ADISP, M_ADISP, M_ADISP,
+ M_ADISP, M_ADISP, M_ADISP, M_ADISP,
+
+ M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
+ M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
+
+ M_ABSW, // 070
+ M_ABSL, // 071
+ M_PCDISP, // 072
+ M_PCINDEXED, // 073
+ M_IMMED, // 074
+ 0L, // 075
+ 0L, // 076
+ 0L, // 077
+ M_ABASE, // 0100
+ M_MEMPOST, // 0101
+ M_MEMPRE, // 0102
+ M_PCBASE, // 0103
+ M_PCMPOST, // 0104
+ M_PCMPRE, // 0105
+ M_AM_USP, // 0106
+ M_AM_SR, // 0107
+ M_AM_CCR, // 0110
+ M_AM_NONE // 0111
+}; // 0112 length
+
+//
+// --- Initialize Line Processor -------------------------------------------------------------------
+//
+
+void init_procln(void) {
+ disabled = 0;
+ ifent = &ifent0;
+ f_ifent = ifent0.if_prev = NULL;
+ ifent0.if_state = 0;
+}
+
+//
+// --- Line Processor ------------------------------------------------------------------------------
+//
+
+void assemble(void) {
+ int state; // Keyword machine state (output)
+ int j; // Random int, must be fast
+ char *p; // Random char ptr, must be fast
+ TOKEN *tk; // First token in line
+ char *label; // Symbol (or NULL)
+ char *equate; // Symbol (or NULL)
+ int labtyp = 0; // Label type (':', DCOLON)
+ int equtyp = 0; // Equ type ('=', DEQUALS)
+ VALUE eval; // Expression value
+ WORD eattr; // Expression attributes
+ SYM *esym; // External symbol involved in expr.
+ WORD siz = 0; // Size suffix to mnem/diretve/macro
+ LONG amsk0, amsk1; // Address-type masks for ea0, ea1
+ MNTAB *m; // Code generation table pointer
+ SYM *sy, *sy2; // Symbol (temp usage)
+ char *opname = NULL; // Name of dirctve/mnemonic/macro
+ int listflag; // 0: Don't call listeol()
+ int as68mode = 0; // 1: Handle multiple labels
+ WORD rmask; // Register list, for REG
+ int registerbank; // RISC register bank
+ int riscreg; // RISC register
+
+ listflag = 0; // Initialise listing flag
+
+ loop: // Line processing loop label
+
+ if(tokln() == TKEOF) { // Get another line of tokens
+ if(list_flag && listflag) // Flush last line of source
+ listeol();
+ if(ifent->if_prev != NULL) // Check conditional token
+ error("hit EOF without finding matching .endif");
+ return;
+ }
+
+ if(list_flag) {
+ if(listflag && listing > 0) listeol(); // Tell listing generator about EOL
+ lstout((char)(disabled ? '-' : lntag)); // Prepare new line for listing
+ listflag = 1; // OK to call `listeol' now
+ just_bss = 0; // Reset just_bss mode
+ }
+
+ state = -3; // No keyword (just EOL)
+ label = NULL; // No label
+ lab_sym = NULL; // No (exported) label
+ equate = NULL; // No equate
+ tk = tok; // Save first token in line
+ pcloc = (VALUE)sloc; // Set beginning-of-line PC
+
+ loop1: // Internal line processing loop
+
+ if(*tok == EOL) // Restart loop if end-of-line
+ goto loop;
+
+ if(*tok != SYMBOL) { // First token MUST be a symbol
+ error(syntax_error);
+ goto loop;
+ }
+
+ j = (int)tok[2]; // Skip equates (normal statements)
+ if(j == '=' || j == DEQUALS || j == SET || j == REG || j == EQUREG || j == CCDEF) {
+ equate = (char *)tok[1];
+ equtyp = j;
+ tok += 3;
+ goto normal;
+ }
+
+ if(j == ':' || j == DCOLON) { // Skip past label (but record it)
+
+ as68label:
+
+ label = (char *)tok[1]; // Get label name
+ labtyp = tok[2]; // Get label type
+ tok += 3; // Go to next line token
+
+ // Handle multiple labels; if there's another label, go process it,
+ // and come back at `as68label' above.
+ if(as68_flag) {
+ as68mode = 0;
+ if(*tok == SYMBOL && tok[2] == ':') {
+ as68mode = 1;
+ goto do_label;
+ }
+ }
+ }
+
+ if(*tok == EOL) // EOL is legal here...
+ goto normal;
+
+ if(*tok++ != SYMBOL) { // Next token MUST be a symbol
+ error(syntax_error);
+ goto loop;
+ }
+ opname = p = (char *)*tok++; // Store opcode name here
+
+ // Check to see if the SYMBOL is a keyword (a mnemonic or directive).
+ // On output, `state' will have one of the values:
+ // -3 there was no symbol (EOL)
+ // -2..-1 the symbol didn't match any keyword
+ // 0..499 vanilla directives (dc, ds, etc.)
+ // 500..999 electric directives (macro, rept, etc.)
+ // 1000..+ mnemonics (move, lsr, etc.)
+ for(state = 0; state >= 0;) {
+ j = mnbase[state] + (int)tolowertab[*p];
+ if(mncheck[j] != state) { // Reject, character doesn't match
+ state = -1; // No match
+ break;
+ }
+ if(!*++p) { // Must accept or reject at EOS
+ state = mnaccept[j]; // (-1 on no terminal match)
+ break;
+ }
+ state = mntab[j];
+ }
+
+ // Check for ".b" ".w" ".l" after directive, macro or mnemonic.
+ siz = SIZN;
+ if(*tok == DOTW)
+ siz = SIZW, ++tok;
+ else if(*tok == DOTL)
+ siz = SIZL, ++tok;
+ else if(*tok == DOTB)
+ siz = SIZB, ++tok;
+
+ // Do special directives (500..999) (These must be handled in "real time")
+ if(state >= 500 && state < 1000)
+ switch(state) {
+ case MN_IF:
+ d_if();
+ goto loop;
+ case MN_ELSE:
+ d_else();
+ goto loop;
+ case MN_ENDIF:
+ d_endif();
+ goto loop;
+ case MN_IIF: // .iif --- immediate if
+ if(disabled || expr(exprbuf, &eval, &eattr, &esym) != OK)
+ goto loop;
+ if(!(eattr & DEFINED)) {
+ error(undef_error);
+ goto loop;
+ }
+ if(*tok++ != ',') {
+ error(comma_error);
+ goto loop;
+ }
+ if(eval == 0)
+ goto loop;
+ goto loop1;
+ case MN_MACRO: // .macro --- macro definition
+ if(!disabled) {
+ if(label != NULL)
+ warn(lab_ignored);
+ defmac();
+ }
+ goto loop;
+ case MN_EXITM: // .exitm --- exit macro
+ case MN_ENDM: // .endm --- same as .exitm
+ if(!disabled) {
+ if(label != NULL)
+ warn(lab_ignored);
+ exitmac();
+ }
+ goto loop;
+ case MN_REPT:
+ if(!disabled) {
+ if(label != NULL)
+ warn(lab_ignored);
+ defrept();
+ }
+ goto loop;
+ case MN_ENDR:
+ if(!disabled)
+ error("mis-nested .endr");
+ goto loop;
+ }
+
+ normal:
+
+ if(disabled) // Conditionally disabled code
+ goto loop;
+
+ // Do equates
+ if(equate != NULL) {
+ j = 0; // Pick global or local sym enviroment
+ if(*equate == '.')
+ j = curenv;
+
+ sy = lookup(equate, LABEL, j);
+ if(sy == NULL) {
+ sy = newsym(equate, LABEL, j);
+ sy->sattr = 0;
+ if(equtyp == DEQUALS) {
+ if(j) { // Can't GLOBAL a local symbol
+ error(locgl_error);
+ goto loop;
+ }
+ sy->sattr = GLOBAL;
+ }
+ } else if((sy->sattr & DEFINED) && equtyp != SET) {
+ if((equtyp == EQUREG) && (sy->sattre & UNDEF_EQUR)) {
+ sy->sattre |= ~UNDEF_EQUR;
+ sy->svalue = 0;
+ } else if((equtyp == CCDEF) && (sy->sattre & UNDEF_CC)) {
+ sy->sattre |= ~UNDEF_CC;
+ sy->svalue = 0;
+ } else {
+ errors("multiple equate to '%s'", sy->sname);
+ goto loop;
+ }
+ }
+
+ // Put symbol in "order of definition" list
+ if(!(sy->sattr & SDECLLIST)) sym_decl(sy);
+
+ // Parse value to equate symbol to;
+ // o .equr
+ // o .reg
+ // o everything else
+ if(equtyp == EQUREG) {
+ if(!rgpu && !rdsp) { // Check that we are in a RISC section
+ error(".equr/.regequ must be defined in .gpu/.dsp section");
+ goto loop;
+ }
+ if((*tok >= KW_R0) && (*tok <= KW_R31)) { // Check for register to equate to
+ sy->sattre = EQUATEDREG | RISCSYM; // Mark as equated register
+ riscreg = (*tok - KW_R0);
+ sy->sattre |= (riscreg << 8); // Store register number
+ if((tok[1] == ',') && (tok[2] == CONST)) {
+ tok += 3;
+ if(*tok == 0) registerbank = BANK_0;
+ else if(*tok == 1) registerbank = BANK_1;
+ else registerbank = BANK_N;
+ } else {
+ registerbank = BANK_N;
+ }
+ sy->sattre |= regbank; // Store register bank
+ eattr = ABS | DEFINED | GLOBAL;
+ eval = 0x80000080 + (riscreg) + (registerbank << 8);
+ tok++;
+ } else if(tok[0] == SYMBOL) { // Checking for a register symbol
+ sy2 = lookup((char *)tok[1], LABEL, j);
+ if(!sy2 || !(sy2->sattre & EQUATEDREG)) { // Make sure symbol is a valid equreg
+ error("invalid GPU/DSP .equr/.regequ definition");
+ goto loop;
+ } else {
+ eattr = ABS | DEFINED | GLOBAL; // Copy symbols attributes
+ sy->sattre = sy2->sattre;
+ eval = (sy2->svalue & 0xFFFFF0FF);
+ tok += 2;
+ }
+ } else {
+ error("invalid GPU/DSP .equr/.regequ definition");
+ goto loop;
+ }
+ } else if(equtyp == REG) {
+ if(reglist(&rmask) < 0)
+ goto loop;
+ eval = (VALUE)rmask;
+ eattr = ABS | DEFINED;
+ } else if(equtyp == CCDEF) {
+ sy->sattre |= EQUATEDCC;
+ eattr = ABS | DEFINED | GLOBAL;
+ if(tok[0] == SYMBOL) {
+ sy2 = lookup((char *)tok[1], LABEL, j);
+ if(!sy2 || !(sy2->sattre & EQUATEDCC)) {
+ error("invalid gpu/dsp .ccdef definition");
+ goto loop;
+ } else {
+ eattr = ABS | DEFINED | GLOBAL;
+ sy->sattre = sy2->sattre;
+ eval = sy2->svalue;
+ tok += 2;
+ }
+ } else
+ if(expr(exprbuf, &eval, &eattr, &esym) != OK)
+ goto loop;
+ } else if(*tok == SYMBOL) { //equ a equr
+ sy2 = lookup((char *)tok[1], LABEL, j);
+ if(sy2 && (sy2->sattre & EQUATEDREG)) {
+ sy->stype = sy2->stype;
+ sy->sattr = sy2->sattr;
+ sy->sattre = sy2->sattre;
+ sy->svalue = (sy2->svalue & 0xFFFFF0FF);
+ goto loop;
+ } else
+ if(expr(exprbuf, &eval, &eattr, &esym) != OK)
+ goto loop;
+ } else
+ if(expr(exprbuf, &eval, &eattr, &esym) != OK)
+ goto loop;
+
+ if(!(eattr & DEFINED)) {
+ error(undef_error);
+ goto loop;
+ }
+
+
+ sy->sattr |= eattr | EQUATED; // Symbol inherits value and attributes
+ sy->svalue = eval;
+ if(list_flag) // Put value in listing
+ listvalue(eval);
+
+ at_eol(); // Must be at EOL now
+ goto loop;
+ }
+
+ // Do labels
+ if(label != NULL) {
+
+ do_label:
+
+ j = 0;
+ if(*label == '.')
+ j = curenv;
+ sy = lookup(label, LABEL, j);
+
+ if(sy == NULL) {
+ sy = newsym(label, LABEL, j);
+ sy->sattr = 0;
+ sy->sattre = RISCSYM;
+ } else if(sy->sattr & DEFINED) {
+ errors("multiply-defined label '%s'", label);
+ goto loop;
+ }
+
+ // Put symbol in "order of definition" list
+ if(!(sy->sattr & SDECLLIST)) sym_decl(sy);
+
+ if(orgactive) {
+ sy->svalue = orgaddr;
+ sy->sattr |= ABS | DEFINED | EQUATED;
+ } else {
+ sy->svalue = sloc;
+ sy->sattr |= DEFINED | cursect;
+ }
+
+ lab_sym = sy;
+ if(!j)
+ ++curenv;
+
+ if(labtyp == DCOLON) { // Make label global
+ if(j) {
+ error(locgl_error);
+ goto loop;
+ }
+ sy->sattr |= GLOBAL;
+ }
+
+ // If we're in as68 mode, and there's another label, go back and handle it
+ if(as68_flag && as68mode)
+ goto as68label;
+ }
+
+ // Punt on EOL
+ if(state == -3)
+ goto loop;
+
+ // If we are in GPU or DSP mode and still in need of a mnemonic then search for one
+ if((rgpu || rdsp) && (state < 0 || state >= 1000)) {
+ for(state = 0, p = opname; state >= 0;) {
+ j = mrbase[state] + (int)tolowertab[*p];
+ if(mrcheck[j] != state) { // Reject, character doesn't match
+ state = -1; // No match
+ break;
+ }
+
+ if(!*++p) { // Must accept or reject at EOS
+ state = mraccept[j]; // (-1 on no terminal match)
+ break;
+ }
+ state = mrtab[j];
+ }
+
+ // Call RISC code generator if we found a mnemonic
+ if(state >= 3000) {
+ risccg(state);
+ goto loop;
+ }
+ }
+
+ // Invoke macro or complain about bad mnemonic
+ if(state < 0) {
+ if((sy = lookup(opname, MACRO, 0)) != NULL)
+ invokemac(sy, siz);
+ else errors("unknown op '%s'", opname);
+ goto loop;
+ }
+
+ // Call directive handlers
+ if(state < 500) {
+ (*dirtab[state])(siz);
+ goto loop;
+ }
+
+ // Do mnemonics
+ // o can't deposit instrs in BSS or ABS
+ // o do automatic .EVEN for instrs
+ // o allocate space for largest possible instr
+ // o can't do ".b" operations with an address register
+ if(scattr & SBSS) {
+ error("cannot initialize non-storage (BSS) section");
+ goto loop;
+ }
+
+ if(sloc & 1) // Automatic .even
+ auto_even();
+
+ if(challoc - ch_size < 18) // Make sure have space in current chunk
+ chcheck(0L);
+
+ m = &machtab[state - 1000];
+ if(m->mnattr & CGSPECIAL) { // Call special-mode handler
+ (*m->mnfunc)(m->mninst, siz);
+ goto loop;
+ }
+
+ if(amode(1) < 0) // Parse 0, 1 or 2 addr modes
+ goto loop;
+
+ if(*tok != EOL)
+ error(extra_stuff);
+
+ amsk0 = amsktab[am0];
+ amsk1 = amsktab[am1];
+
+ // Catch attempts to use ".B" with an address register (yes, this check does work at this level)
+ if(siz == SIZB && (am0 == AREG || am1 == AREG)) {
+ error("cannot use '.b' with an address register");
+ goto loop;
+ }
+
+ for(;;) {
+ if((m->mnattr & siz) && (amsk0 & m->mn0) != 0 && (amsk1 & m->mn1) != 0) {
+ (*m->mnfunc)(m->mninst, siz);
+ goto loop;
+ }
+ m = &machtab[m->mncont];
+ }
+}
+
+//
+// --- .if, Start Conditional Assembly -------------------------------------------------------------
+//
+
+int d_if(void) {
+ IFENT *rif;
+ WORD eattr;
+ VALUE eval;
+ SYM *esym;
+
+ // Alloc an IFENTRY
+ if((rif = f_ifent) == NULL) rif = (IFENT *)amem((LONG)sizeof(IFENT));
+ else f_ifent = rif->if_prev;
+
+ rif->if_prev = ifent;
+ ifent = rif;
+
+ if(!disabled) {
+ if(expr(exprbuf, &eval, &eattr, &esym) != OK) return(0);
+ if((eattr & DEFINED) == 0) return(error(undef_error));
+ disabled = !eval;
+ }
+ rif->if_state = (WORD)disabled;
+ return(0);
+}
+
+//
+// --- .else, Do Alternate Case For .if ------------------------------------------------------------
+//
+
+int d_else(void) {
+ IFENT *rif;
+
+ rif = ifent;
+
+ if(rif->if_prev == NULL) return(error("mismatched .else"));
+
+ if(disabled) disabled = rif->if_prev->if_state;
+ else disabled = 1;
+
+ rif->if_state = (WORD)disabled;
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// .endif, End of conditional assembly block
+// This is also called by fpop() to pop levels of IFENTs in case a macro or include file exits
+// early with `exitm' or `end'.
+// -------------------------------------------------------------------------------------------------
+//
+
+int d_endif(void) {
+ IFENT *rif;
+
+ rif = ifent;
+ if(rif->if_prev == NULL) return(error("mismatched .endif"));
+
+ ifent = rif->if_prev;
+ disabled = rif->if_prev->if_state;
+ rif->if_prev = f_ifent;
+ f_ifent = rif;
+ return(0);
+}
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// PROCLN.H - Line Processing
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __PROCLN_H__
+#define __PROCLN_H__
+
+#include "rmac.h"
+#include "token.h"
+
+// Globals, externals etc
+extern IFENT *ifent;
+extern char *comma_error;
+extern char *locgl_error;
+extern char *syntax_error;
+extern int just_bss;
+extern VALUE pcloc;
+extern IFENT *ifent;
+extern SYM *lab_sym;
+extern char extra_stuff[];
+extern LONG amsktab[];
+
+// Prototypes
+void init_procln(void);
+void assemble(void);
+int eject(void);
+int d_if(void);
+int d_else(void);
+int d_endif(void);
+int at_eol(void);
+
+#endif // __PROCLN_H__
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RISCA.C - GPU/DSP Assembler
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "risca.h"
+#include "error.h"
+#include "sect.h"
+#include "token.h"
+#include "expr.h"
+#include "direct.h"
+#include "mark.h"
+#include "amode.h"
+
+#define DEF_MR // Declar keyword values
+#include "risckw.h" // Incl generated risc keywords
+
+#define DEF_KW // Declare keyword values
+#include "kwtab.h" // Incl generated keyword tables & defs
+
+unsigned altbankok = 0; // Ok to use alternate register bank
+unsigned orgactive = 0; // RISC org directive active
+unsigned orgaddr = 0; // Org'd address
+unsigned orgwarning = 0; // Has an ORG warning been issued
+int jpad = 0;
+unsigned previousop = 0; // Used for NOP padding checks
+unsigned currentop = 0; // Used for NOP padding checks
+unsigned mjump_defined, mjump_dest; // mjump macro flags, values etc
+
+char reg_err[] = "missing register R0...R31";
+
+// Jaguar Jump Condition Names
+char condname[MAXINTERNCC][5] = {
+ "NZ", "Z", "NC", "NCNZ", "NCZ", "C", "CNZ", "CZ", "NN", "NNNZ", "NNZ", "N", "N_NZ", "N_Z ",
+ "T", "A", "NE", "EQ", "CC", "HS", "HI", "CS", "LO", "PL", "MI", "F"
+};
+
+// Jaguar Jump Condition Numbers
+char condnumber[] = {1, 2, 4, 5, 6, 8, 9, 10, 20, 21, 22, 24, 25, 26,
+ 0, 0, 1, 2, 4, 4, 5, 8, 8, 20, 24, 31};
+
+struct opcoderecord roptbl[] = {
+ { MR_ADD, RI_TWO, 0 },
+ { MR_ADDC, RI_TWO, 1 },
+ { MR_ADDQ, RI_NUM_32, 2 },
+ { MR_ADDQT, RI_NUM_32, 3 },
+ { MR_SUB, RI_TWO, 4 },
+ { MR_SUBC, RI_TWO, 5 },
+ { MR_SUBQ, RI_NUM_32, 6 },
+ { MR_SUBQT, RI_NUM_32, 7 },
+ { MR_NEG, RI_ONE, 8 },
+ { MR_AND, RI_TWO, 9 },
+ { MR_OR, RI_TWO, 10 },
+ { MR_XOR, RI_TWO, 11 },
+ { MR_NOT, RI_ONE, 12 },
+ { MR_BTST, RI_NUM_31, 13 },
+ { MR_BSET, RI_NUM_31, 14 },
+ { MR_BCLR, RI_NUM_31, 15 },
+ { MR_MULT, RI_TWO, 16 },
+ { MR_IMULT, RI_TWO, 17 },
+ { MR_IMULTN, RI_TWO, 18 },
+ { MR_RESMAC, RI_ONE, 19 },
+ { MR_IMACN, RI_TWO, 20 },
+ { MR_DIV, RI_TWO, 21 },
+ { MR_ABS, RI_ONE, 22 },
+ { MR_SH, RI_TWO, 23 },
+ { MR_SHLQ, RI_NUM_32, 24 + SUB32 },
+ { MR_SHRQ, RI_NUM_32, 25 },
+ { MR_SHA, RI_TWO, 26 },
+ { MR_SHARQ, RI_NUM_32, 27 },
+ { MR_ROR, RI_TWO, 28 },
+ { MR_RORQ, RI_NUM_32, 29 },
+ { MR_ROLQ, RI_NUM_32, 29 + SUB32 },
+ { MR_CMP, RI_TWO, 30 },
+ { MR_CMPQ, RI_NUM_15, 31 },
+ { MR_SAT8, RI_ONE, 32 + GPUONLY },
+ { MR_SUBQMOD, RI_NUM_32, 32 + DSPONLY },
+ { MR_SAT16, RI_ONE, 33 + GPUONLY },
+ { MR_SAT16S, RI_ONE, 33 + DSPONLY },
+ { MR_MOVEQ, RI_NUM_31, 35 },
+ { MR_MOVETA, RI_TWO, 36 },
+ { MR_MOVEFA, RI_TWO, 37 },
+ { MR_MOVEI, RI_MOVEI, 38 },
+ { MR_LOADB, RI_LOADN, 39 },
+ { MR_LOADW, RI_LOADN, 40 },
+ { MR_LOADP, RI_LOADN, 42 + GPUONLY },
+ { MR_SAT32S, RI_ONE, 42 + DSPONLY },
+ { MR_STOREB, RI_STOREN, 45 },
+ { MR_STOREW, RI_STOREN, 46 },
+ { MR_STOREP, RI_STOREN, 48 + GPUONLY },
+ { MR_MIRROR, RI_ONE, 48 + DSPONLY },
+ { MR_JUMP, RI_JUMP, 52 },
+ { MR_JR, RI_JR, 53 },
+ { MR_MMULT, RI_TWO, 54 },
+ { MR_MTOI, RI_TWO, 55 },
+ { MR_NORMI, RI_TWO, 56 },
+ { MR_NOP, RI_NONE, 57 },
+ { MR_SAT24, RI_ONE, 62 },
+ { MR_UNPACK, RI_ONE, 63 + GPUONLY },
+ { MR_PACK, RI_ONE, 63 + GPUONLY },
+ { MR_ADDQMOD, RI_NUM_32, 63 + DSPONLY },
+ { MR_MOVE, RI_MOVE, 0 },
+ { MR_LOAD, RI_LOAD, 0 },
+ { MR_STORE, RI_STORE, 0 }
+};
+
+//
+// --- Convert a String to Uppercase ---------------------------------------------------------------
+//
+
+void strtoupper(char *s) {
+ while(*s) {
+ *s = (char)(toupper(*s));
+ s++;
+ }
+}
+
+//
+// --- Build RISC Instruction Word -----------------------------------------------------------------
+//
+
+void risc_instruction_word(unsigned short parm, int reg1, int reg2) {
+ int value = 0xE400;
+
+ previousop = currentop; // Opcode tracking for nop padding
+ currentop = parm;
+
+ if(!orgwarning) { // Check for absolute address setting
+ if(!orgactive && !in_main) {
+ warn("GPU/DSP code outside of absolute section");
+ orgwarning = 1;
+ }
+ }
+
+ if(jpad) { // JPAD directive
+ // JUMP JR NOP
+ if(((previousop == 52) || (previousop == 53)) && (currentop != 57))
+ D_word(value); // Insert NOP
+ } else {
+ // JUMP JR
+ if((previousop == 52) || (previousop == 53)) {
+ switch(currentop) {
+ case 38: warn("NOP inserted before MOVEI instruction."); D_word(value); break;
+ case 53: warn("NOP inserted before JR instruction."); D_word(value); break;
+ case 52: warn("NOP inserted before JUMP instruction."); D_word(value); break;
+ case 51: warn("NOP inserted before MOVE PC instruction."); D_word(value); break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if(currentop == 20) { // IMACN checks
+ if((previousop != 18) && (previousop != 20)) {
+ error("IMULTN/IMACN instruction must preceed IMACN instruction");
+ }
+ }
+
+ if(currentop == 19) { // RESMAC checks
+ if(previousop != 20) {
+ error("IMACN instruction must preceed RESMAC instruction");
+ }
+ }
+
+ value =((parm & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
+ D_word(value);
+}
+
+//
+// --- Get a RISC Register -------------------------------------------------------------------------
+//
+
+int getregister(WORD rattr) {
+ VALUE eval; // Expression value
+ WORD eattr; // Expression attributes
+ SYM *esym; // External symbol involved in expr.
+ TOKEN r_expr[EXPRSIZE]; // Expression token list
+ WORD defined; // Symbol defined flag
+
+ if(expr(r_expr, &eval, &eattr, &esym) != OK) {
+ error("malformed opcode");
+ return(ERROR);
+ } else {
+ defined = (WORD)(eattr & DEFINED);
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+ if(!defined) {
+ fixup((WORD)(FU_WORD|rattr), sloc, r_expr);
+ return(0);
+ } else {
+ if((eval >= 0) && (eval <= 31)) { // Check for specified register, r0->r31
+ return(eval);
+ } else {
+ error(reg_err);
+ return(ERROR);
+ }
+ }
+ }
+
+ return(ERROR);
+}
+
+//
+// --- Do RISC Code Generation ---------------------------------------------------------------------
+//
+
+int risccg(int state) {
+ unsigned short parm; // Opcode parameters
+ unsigned type; // Opcode type
+ int reg1; // Register 1
+ int reg2; // Register 2
+ int val = 0; // Constructed value
+ char scratch[80];
+ SYM *ccsym;
+ SYM *sy;
+ int i; // Iterator
+ int t, c;
+ WORD tdb;
+ unsigned locptr = 0; // Address location pointer
+ unsigned page_jump = 0; // Memory page jump flag
+ VALUE eval; // Expression value
+ WORD eattr; // Expression attributes
+ SYM *esym; // External symbol involved in expr.
+ TOKEN r_expr[EXPRSIZE]; // Expression token list
+ WORD defined; // Symbol defined flag
+ WORD attrflg;
+ int indexed; // Indexed register flag
+
+ parm = (WORD)(roptbl[state-3000].parm); // Get opcode parameter and type
+ type = roptbl[state-3000].typ;
+
+ // Detect whether the opcode parmeter passed determines that the opcode is specific to only one
+ // of the RISC processors and ensure it is legal in the current code section.
+ // If not then error and return.
+ if(((parm & GPUONLY) && rdsp) || ((parm & DSPONLY) && rgpu) ) {
+ error("opcode is not valid in this code section");
+ return(ERROR);
+ }
+
+ // Process RISC opcode
+ switch(type) {
+ // No operand instructions
+ // NOP
+ case RI_NONE:
+ risc_instruction_word(parm, 0, 0);
+ break;
+ // Single operand instructions (Rd)
+ // ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S, UNPACK
+ case RI_ONE:
+ reg2 = getregister(FU_REGTWO);
+ at_eol();
+ risc_instruction_word(parm, parm >> 6, reg2);
+ break;
+ // Two operand instructions (Rs,Rd)
+ // ADD, ADDC, AND, CMP, DIV, IMACN, IMULT, IMULTN, MOVEFA, MOVETA, MULT, MMULT,
+ // MTOI, NORMI, OR, ROR, SH, SHA, SUB, SUBC, XOR
+ case RI_TWO:
+ if(parm == 37) altbankok = 1; // MOVEFA
+ reg1 = getregister(FU_REGONE);
+ CHECK_COMMA;
+ if(parm == 36) altbankok = 1; // MOVETA
+ reg2 = getregister(FU_REGTWO);
+ at_eol();
+ risc_instruction_word(parm, reg1, reg2);
+ break;
+ // Numeric operand (n,Rd) where n = -16..+15
+ // CMPQ
+ case RI_NUM_15:
+ // Numeric operand (n,Rd) where n = 0..31
+ // BCLR, BSET, BTST, MOVEQ
+ case RI_NUM_31:
+ // Numeric operand (n,Rd) where n = 1..32
+ // ADDQ, ADDQMOD, ADDQT, SHARQ, SHLQ, SHRQ, SUBQ, SUBQMOD, SUBQT, ROLQ, RORQ
+ case RI_NUM_32:
+ switch(type) {
+ case RI_NUM_15: reg1 = -16; reg2 = 15; attrflg = FU_NUM15; break;
+ default:
+ case RI_NUM_31: reg1 = 0; reg2 = 31; attrflg = FU_NUM31; break;
+ case RI_NUM_32: reg1 = 1; reg2 = 32; attrflg = FU_NUM32; break;
+ }
+ if(parm & SUB32) attrflg |= FU_SUB32;
+ if(*tok == '#') {
+ ++tok;
+ if(expr(r_expr, &eval, &eattr, &esym) != OK)
+ goto malformed;
+ else {
+ defined = (WORD)(eattr & DEFINED);
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+ if(!defined) {
+ fixup((WORD)(FU_WORD|attrflg), sloc, r_expr);
+ reg1 = 0;
+ } else {
+ if((int)eval < reg1 || (int)eval > reg2) {
+ error("constant out of range");
+ return(ERROR);
+ }
+ if(parm & SUB32)
+ reg1 = 32 - eval;
+ else if(type == RI_NUM_32)
+ reg1 = (reg1 == 32) ? 0 : eval;
+ else
+ reg1 = eval;
+ }
+ }
+ } else goto malformed;
+ CHECK_COMMA;
+ reg2 = getregister(FU_REGTWO);
+ at_eol();
+ risc_instruction_word(parm, reg1, reg2);
+ break;
+ // Move Immediate - n,Rn - n in Second Word
+ case RI_MOVEI:
+ if(*tok == '#') {
+ ++tok;
+ if(expr(r_expr, &eval, &eattr, &esym) != OK) {
+ malformed:
+ error("malformed opcode");
+ return(ERROR);
+ } else {
+ // Opcode tracking for nop padding
+ previousop = currentop;
+ currentop = parm;
+ // JUMP or JR
+ if((previousop == 52) || (previousop == 53) && !jpad) {
+ warn("NOP inserted before MOVEI instruction.");
+ D_word(0xE400);
+ }
+ tdb = (WORD)(eattr & TDB);
+ defined = (WORD)(eattr & DEFINED);
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+ if(!defined) {
+ fixup(FU_LONG|FU_MOVEI, sloc + 2, r_expr);
+ eval = 0;
+ } else {
+ if(tdb) {
+ rmark(cursect, sloc + 2, tdb, MLONG|MMOVEI, NULL);
+ }
+ }
+ val = eval;
+ // Store the defined flags and value of the movei when used in mjump
+ if(mjump_align) {
+ mjump_defined = defined;
+ mjump_dest = val;
+ }
+ }
+ } else goto malformed;
+ ++tok;
+ reg2 = getregister(FU_REGTWO);
+ at_eol();
+ D_word((((parm & 0x3F) << 10) + reg2));
+ val = ((val >> 16) & 0x0000FFFF) | ((val << 16) & 0xFFFF0000);
+ D_long(val);
+ break;
+ case RI_MOVE: // PC,Rd or Rs,Rd
+ if(*tok == KW_PC) {
+ parm = 51;
+ reg1 = 0;
+ ++tok;
+ } else {
+ parm = 34;
+ reg1 = getregister(FU_REGONE);
+ }
+ CHECK_COMMA;
+ reg2 = getregister(FU_REGTWO);
+ at_eol();
+ risc_instruction_word(parm, reg1, reg2);
+ break;
+ // (Rn),Rn = 41 / (R14/R15+n),Rn = 43/44 / (R14/R15+Rn),Rn = 58/59
+ case RI_LOAD:
+ indexed = 0;
+ parm = 41;
+ if(*tok != '(') goto malformed;
+ ++tok;
+ if((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')'))
+ indexed = (*tok - KW_R0);
+ if(*tok == SYMBOL) {
+ sy = lookup((char *)tok[1], LABEL, 0);
+ if(!sy) {
+ error(reg_err);
+ return(ERROR);
+ }
+ if(sy->sattre & EQUATEDREG)
+ if(((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15) && (*(tok+2) != ')')) {
+ indexed = (sy->svalue & 0x1F);
+ ++tok;
+ }
+ }
+ if(!indexed) {
+ reg1 = getregister(FU_REGONE);
+ } else {
+ reg1 = indexed;
+ indexed = 0;
+ ++tok;
+ if(*tok == '+') {
+ parm = (WORD)(reg1 - 14 + 58);
+ tok++;
+ if(*tok >= KW_R0 && *tok <= KW_R31) {
+ indexed = 1;
+ }
+ if(*tok == SYMBOL) {
+ sy = lookup((char *)tok[1], LABEL, 0);
+ if(!sy) {
+ error(reg_err);
+ return(ERROR);
+ }
+ if(sy->sattre & EQUATEDREG) {
+ indexed = 1;
+ }
+ }
+ if(indexed) {
+ reg1 = getregister(FU_REGONE);
+ } else {
+ if(expr(r_expr, &eval, &eattr, &esym) != OK) {
+ goto malformed;
+ } else {
+ tdb = (WORD)(eattr & TDB);
+ defined = (WORD)(eattr & DEFINED);
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+ if(!defined) {
+ error("constant expected");
+ return(ERROR);
+ //fixup(FU_WORD|FU_REGONE, sloc, r_expr);
+ reg1 = 0;
+ } else {
+ reg1 = eval;
+ if(reg1 == 0) {
+ reg1 = 14+(parm-58);
+ parm = 41;
+ warn("NULL offset removed");
+ } else {
+ if(reg1 < 1 || reg1 > 32) {
+ error("constant out of range");
+ return(ERROR);
+ }
+ if(reg1 == 32) reg1 = 0;
+ parm = (WORD)(parm - 58 + 43);
+ }
+ }
+ }
+ }
+ } else {
+ reg1 = getregister(FU_REGONE);
+ }
+ }
+ if(*tok != ')') goto malformed;
+ ++tok;
+ CHECK_COMMA;
+ reg2 = getregister(FU_REGTWO);
+ at_eol();
+ risc_instruction_word(parm, reg1, reg2);
+ break;
+ // Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
+ case RI_STORE:
+ parm = 47;
+ reg1 = getregister(FU_REGONE);
+ CHECK_COMMA;
+ if(*tok != '(') goto malformed;
+ ++tok;
+ indexed = 0;
+ if((*tok == KW_R14 || *tok == KW_R15) && (*(tok+1) != ')'))
+ indexed = (*tok - KW_R0);
+ if(*tok == SYMBOL) {
+ sy = lookup((char *)tok[1], LABEL, 0);
+ if(!sy) {
+ error(reg_err);
+ return(ERROR);
+ }
+ if(sy->sattre & EQUATEDREG)
+ if(((sy->svalue & 0x1F) == 14 || (sy->svalue & 0x1F) == 15) && (*(tok+2) != ')')) {
+ indexed = (sy->svalue & 0x1F);
+ ++tok;
+ }
+ }
+ if(!indexed) {
+ reg2 = getregister(FU_REGTWO);
+ } else {
+ reg2 = indexed;
+ indexed = 0;
+ ++tok;
+ if(*tok == '+') {
+ parm = (WORD)(reg2 - 14 + 60);
+ tok++;
+ if(*tok >= KW_R0 && *tok <= KW_R31) {
+ indexed = 1;
+ }
+ if(*tok == SYMBOL) {
+ sy = lookup((char *)tok[1], LABEL, 0);
+ if(!sy) {
+ error(reg_err);
+ return(ERROR);
+ }
+ if(sy->sattre & EQUATEDREG) {
+ indexed = 1;
+ }
+ }
+ if(indexed) {
+ reg2 = getregister(FU_REGTWO);
+ } else {
+ if(expr(r_expr, &eval, &eattr, &esym) != OK) {
+ goto malformed;
+ } else {
+ tdb = (WORD)(eattr & TDB);
+ defined = (WORD)(eattr & DEFINED);
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+ if(!defined) {
+ fixup(FU_WORD|FU_REGTWO, sloc, r_expr);
+ reg2 = 0;
+ } else {
+ reg2 = eval;
+ if(reg2 == 0 ) {
+ reg2 = 14+(parm-60);
+ parm = 47;
+ warn("NULL offset removed");
+ } else {
+ if(reg2 < 1 || reg2 > 32) {
+ error("constant out of range");
+ return(ERROR);
+ }
+ if(reg2 == 32) reg2 = 0;
+ parm = (WORD)(parm - 60 + 49);
+ }
+ }
+ }
+ }
+ } else {
+ reg2 = getregister(FU_REGTWO);
+ }
+ }
+ if(*tok != ')') goto malformed;
+ ++tok;
+ at_eol();
+ risc_instruction_word(parm, reg2, reg1);
+ break;
+ // LOADB/LOADP/LOADW (Rn),Rn
+ case RI_LOADN:
+ if(*tok != '(') goto malformed;
+ ++tok;
+ reg1 = getregister(FU_REGONE);
+ if(*tok != ')') goto malformed;
+ ++tok;
+ CHECK_COMMA;
+ reg2 = getregister(FU_REGTWO);
+ at_eol();
+ risc_instruction_word(parm, reg1, reg2);
+ break;
+ // STOREB/STOREP/STOREW Rn,(Rn)
+ case RI_STOREN:
+ reg1 = getregister(FU_REGONE);
+ CHECK_COMMA;
+ if(*tok != '(') goto malformed;
+ ++tok;
+ reg2 = getregister(FU_REGTWO);
+ if(*tok != ')') goto malformed;
+ ++tok;
+ at_eol();
+ risc_instruction_word(parm, reg2, reg1);
+ break;
+ case RI_JR: // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
+ case RI_JUMP: // Jump Absolute - cc,(Rs) - reg2=cc
+ // Check to see if there is a comma in the token string. If not then the JR or JUMP should
+ // default to 0, Jump Always
+ t = i = c = 0;
+ while(t != EOL) {
+ t = *(tok + i);
+ if(t == ',') c = 1;
+ i++;
+ }
+ if(c) { // Comma present in token string
+ if(*tok == CONST) { // CC using a constant number
+ ++tok;
+ val = *tok;
+ ++tok;
+ CHECK_COMMA;
+ } else if(*tok == SYMBOL) {
+ val = 99;
+ for(i = 0; i < MAXINTERNCC; i++) {
+ strcpy(scratch, (char *)tok[1]);
+ strtoupper(scratch);
+ if(!strcmp(condname[i], scratch))
+ val = condnumber[i];
+ }
+ if(val == 99) {
+ ccsym = lookup((char *)tok[1], LABEL, 0);
+ if(ccsym && (ccsym->sattre & EQUATEDCC) && !(ccsym->sattre & UNDEF_CC)) {
+ val = ccsym->svalue;
+ } else {
+ error("unknown condition code");
+ return(ERROR);
+ }
+ }
+ tok += 2;
+ CHECK_COMMA;
+ } else if(*tok == '(') {
+ val = 0; // Jump always
+ }
+ } else {
+ val = 0; // Jump always
+ }
+
+ if(val < 0 || val > 31) {
+ error("condition constant out of range");
+ return(ERROR);
+ } else {
+ reg1 = val; // Store condition code
+ }
+ if(type == RI_JR) { // JR cc,n
+ if(expr(r_expr, &eval, &eattr, &esym) != OK)
+ goto malformed;
+ else {
+ tdb = (WORD)(eattr & TDB);
+ defined = (WORD)(eattr & DEFINED);
+ if((challoc - ch_size) < 4)
+ chcheck(4L);
+ if(!defined) {
+ if(in_main) {
+ fixup(FU_WORD|FU_MJR, sloc, r_expr);
+ } else {
+ fixup(FU_WORD|FU_JR, sloc, r_expr);
+ }
+ reg2 = 0;
+ } else {
+ val = eval;
+ if(orgactive) {
+ reg2 = ((int)(val - (orgaddr + 2))) / 2;
+ if((reg2 < -16) || (reg2 > 15))
+ error("PC relative overflow");
+ locptr = orgaddr;
+ } else {
+ reg2 = ((int)(val - (sloc + 2))) / 2;
+ if((reg2 < -16) || (reg2 > 15))
+ error("PC relative overflow");
+ locptr = sloc;
+ }
+ }
+ if(in_main) {
+ if(defined) {
+ if(((locptr >= 0xF03000) && (locptr < 0xF04000) && (val < 0xF03000)) ||
+ ((val >= 0xF03000) && (val < 0xF04000) && (locptr < 0xF03000)) ) {
+ warn("* cannot jump relative between main memory and local gpu ram");
+ } else {
+ page_jump = (locptr & 0xFFFFFF00) - (val & 0xFFFFFF00);
+ if(page_jump) {
+ if(val % 4) {
+ warn("* destination address not aligned for long page jump relative, "
+ "insert a \'nop\' before the destination label/address");
+ }
+ } else {
+ if((val - 2) % 4) {
+ warn("* destination address not aligned for short page jump relative, "
+ "insert a \'nop\' before the destination label/address");
+ }
+ }
+ }
+ }
+ }
+ }
+ risc_instruction_word(parm, reg2, reg1);
+ } else { // JUMP cc, (Rn)
+ if(*tok != '(') goto malformed;
+ ++tok;
+ reg2 = getregister(FU_REGTWO);
+ if(*tok != ')') goto malformed;
+ ++tok;
+ at_eol();
+ if(in_main) {
+ if(!mjump_align) {
+ warn("* \'jump\' is not recommended for .gpumain as destination addresses "
+ "cannot be validated for alignment, use \'mjump\'");
+ locptr = (orgactive) ? orgaddr : sloc;
+ if(locptr % 4) {
+ warn("* source address not aligned for long or short jump, "
+ "insert a \'nop\' before the \'jump\'");
+ }
+ } else {
+ if(mjump_defined) {
+ locptr = (orgactive) ? orgaddr : sloc;
+ page_jump = (locptr & 0xFFFFFF00) - (mjump_dest & 0xFFFFFF00);
+ if(page_jump) {
+ if(mjump_dest % 4) {
+ warn("* destination address not aligned for long page jump, "
+ "insert a \'nop\' before the destination label/address");
+ }
+ } else {
+ if(!(mjump_dest & 0x0000000F) || ((mjump_dest - 2) % 4)) {
+ warn("* destination address not aligned for short page jump, "
+ "insert a \'nop\' before the destination label/address");
+ }
+ }
+ } else {
+ locptr = (orgactive) ? orgaddr : sloc;
+ fwdjump[fwindex++] = locptr;
+ }
+ }
+
+ }
+ risc_instruction_word(parm, reg2, reg1);
+ }
+ break;
+ // Should never get here :D
+ default:
+ error("unknown risc opcode type");
+ return(ERROR);
+ break;
+
+ }
+
+ return(0);
+}
+
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RISCA.H - GPU/DSP Assembler
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __RISCA_H__
+#define __RISCA_H__
+
+#include "rmac.h"
+#include "procln.h"
+
+#define MAXINTERNCC 26 // Maximum internal condition codes
+
+// RISC Instruction Types
+#define RI_NONE 0x0000 // No Operands - NOP
+#define RI_ONE 0x0001 // One Operand - Rd - ABS/NEG/etc
+#define RI_TWO 0x0002 // Two Operands - Rs,Rd - Most Instructions
+#define RI_NUM_15 0x0003 // Numeric Operand - n,Rd - n=-16..+15 - CMPQ
+#define RI_NUM_31 0x0004 // Numeric Operand - n,Rd - n=0..31 - BCLR/BSET/BTST/MOVEQ
+#define RI_NUM_32 0x0005 // Numeric Operand - n,Rd - n=1..32 - ADDQ/SUBQ
+#define RI_JR 0x0006 // Jump Relative - cc,n - n=-16..+15 words, reg2=cc
+#define RI_JUMP 0x0007 // Jump Absolute - cc,(Rs) - reg2=cc
+#define RI_MOVEI 0x0008 // Move Immediate - n,Rn - n in second word
+#define RI_MOVE 0x0009 // MOVE Instruction - PC,Rn / Rn,Rn
+#define RI_LOAD 0x000A // LOAD Instruction - Various Forms
+#define RI_LOADN 0x000B // LOADB/LOADP/LOADW - (Rs),Rd
+#define RI_STORE 0x000C // STORE Instruction - Various Forms
+#define RI_STOREN 0x000D // STOREB/STOREP/STOREM - Rs,(Rd)
+#define RI_MJMP 0x000E // MJMP psuedo instruction
+
+// Supplementry Instruction Flags
+#define SUB32 0x2000 // (n = 32-n)
+#define GPUONLY 0x4000 // Opcode is for the GPU Only
+#define DSPONLY 0x8000 // Opcode is for the DSP Only
+
+#define CHECK_COMMA if(*tok++ != ',') { error(comma_error); return(ERROR); }
+
+// Opcode Specific Data
+struct opcoderecord {
+ short state; // Opcode Name
+ unsigned short typ; // Opcode Type
+ unsigned parm; // Opcode Parameter
+};
+
+// Globals, externals etc
+extern unsigned orgactive;
+extern unsigned orgaddr;
+extern unsigned orgwarning;
+extern unsigned altbankok;
+extern int jpad;
+
+// Prototypes
+int risccg(int);
+int d_orgrisc(void);
+
+#endif // __RISCA_H__
+
--- /dev/null
+#
+# Jaguar RISC mnemonics
+#
+add 3000
+addc 3001
+addq 3002
+addqt 3003
+sub 3004
+subc 3005
+subq 3006
+subqt 3007
+neg 3008
+and 3009
+or 3010
+xor 3011
+not 3012
+btst 3013
+bset 3014
+bclr 3015
+mult 3016
+imult 3017
+imultn 3018
+resmac 3019
+imacn 3020
+div 3021
+abs 3022
+sh 3023
+shlq 3024
+shrq 3025
+sha 3026
+sharq 3027
+ror 3028
+rorq 3029
+rolq 3030
+cmp 3031
+cmpq 3032
+sat8 3033
+subqmod 3034
+sat16 3035
+sat16s 3036
+moveq 3037
+moveta 3038
+movefa 3039
+movei 3040
+loadb 3041
+loadw 3042
+loadp 3043
+sat32s 3044
+storeb 3045
+storew 3046
+storep 3047
+mirror 3048
+jump 3049
+jr 3050
+mmult 3051
+mtoi 3052
+normi 3053
+nop 3054
+sat24 3055
+unpack 3056
+pack 3057
+addqmod 3058
+move 3059
+load 3060
+store 3061
+
--- /dev/null
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC.C - Main Application Code
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+//
+
+#include "rmac.h"
+#include "error.h"
+#include "listing.h"
+#include "procln.h"
+#include "token.h"
+#include "expr.h"
+#include "sect.h"
+#include "mark.h"
+#include "macro.h"
+#include "risca.h"
+#include "direct.h"
+#include "version.h"
+#include "debug.h"
+#include "symbol.h"
+#include "object.h"
+
+int perm_verb_flag; // Permanently verbose, interactive mode
+int list_flag; // "-l" Listing flag on command line
+int verb_flag; // Be verbose about what's going on
+int as68_flag; // as68 kludge mode
+int glob_flag; // Assume undefined symbols are global
+int lsym_flag; // Include local symbols in object file
+int sbra_flag; // Warn about possible short branches
+int obj_format; // Object format flag
+int debug; // [1..9] Enable debugging levels
+int err_flag; // '-e' specified
+int err_fd; // File to write error messages to
+int rgpu, rdsp; // Assembling Jaguar GPU or DSP code
+int list_fd; // File to write listing to
+int regbank; // RISC register bank
+int segpadsize; // Segment padding size
+int in_main; // In main memory flag for GPUMAIN
+int endian; // Processor endianess
+char *objfname; // Object filename pointer
+char *firstfname; // First source filename
+char *cmdlnexec; // Executable name, pointer to ARGV[0]
+char *searchpath; // Search path for include files
+char defname[] = "noname.o"; // Default output filename
+
+// Under Windows and UNIX malloc() is an expensive call, so for small amounts of memory we allocate
+// from a previously allocated buffer.
+
+#define A_AMOUNT 4096 // Amount to malloc() at a time
+#define A_THRESH 64 // Use malloc() for amounts >= A_THRESH
+
+static LONG a_amount; // Amount left at a_ptr
+static char *a_ptr; // Next free chunk
+LONG amemtot; // amem() total of requests
+
+// Qsort; The THRESHold below is the insertion sort threshold, and has been adjusted
+// for records of size 48 bytes.The MTHREShold is where we stop finding a better median.
+
+#define THRESH 4 // Threshold for insertion
+#define MTHRESH 6 // Threshold for median
+
+static int (*qcmp)(); // The comparison routine
+static int qsz; // Size of each record
+static int thresh; // THRESHold in chars
+static int mthresh; // MTHRESHold in chars
+
+// qst: Do a quicksort. First, find the median element, and put that one in the first place as
+// the discriminator. (This "median" is just the median of the first, last and middle elements).
+// (Using this median instead of the first element is a big win). Then, the usual
+// partitioning/swapping, followed by moving the discriminator into the right place. Then,
+// figure out the sizes of the two partions, do the smaller one recursively and the larger one
+// via a repeat of this code. Stopping when there are less than THRESH elements in a partition
+// and cleaning up with an insertion sort (in our caller) is a huge win. All data swaps are done
+// in-line, which is space-losing but time-saving. (And there are only three places where
+// this is done).
+
+static int qst(char *base, char *max) {
+ char c, *i, *j, *jj;
+ int ii;
+ char *mid, *tmp;
+ long lo, hi;
+
+ /*
+ * At the top here, lo is the number of characters of elements in the
+ * current partition. (Which should be max - base).
+ * Find the median of the first, last, and middle element and make
+ * that the middle element. Set j to largest of first and middle.
+ * If max is larger than that guy, then it's that guy, else compare
+ * max with loser of first and take larger. Things are set up to
+ * prefer the middle, then the first in case of ties.
+ */
+ lo = max - base; /* number of elements as chars */
+ do {
+ mid = i = base + qsz * ((lo / qsz) >> 1);
+ if (lo >= mthresh) {
+ j = (qcmp((jj = base), i) > 0 ? jj : i);
+ if (qcmp(j, (tmp = max - qsz)) > 0) {
+ /* switch to first loser */
+ j = (j == jj ? i : jj);
+ if (qcmp(j, tmp) < 0)
+ j = tmp;
+ }
+ if (j != i) {
+ ii = qsz;
+ do {
+ c = *i;
+ *i++ = *j;
+ *j++ = c;
+ } while (--ii);
+ }
+ }
+ /*
+ * Semi-standard quicksort partitioning/swapping
+ */
+ for (i = base, j = max - qsz; ; ) {
+ while (i < mid && qcmp(i, mid) <= 0)
+ i += qsz;
+ while (j > mid) {
+ if (qcmp(mid, j) <= 0) {
+ j -= qsz;
+ continue;
+ }
+ tmp = i + qsz; /* value of i after swap */
+ if (i == mid) {
+ /* j <-> mid, new mid is j */
+ mid = jj = j;
+ } else {
+ /* i <-> j */
+ jj = j;
+ j -= qsz;
+ }
+ goto swap;
+ }
+ if (i == mid) {
+ break;
+ } else {
+ /* i <-> mid, new mid is i */
+ jj = mid;
+ tmp = mid = i; /* value of i after swap */
+ j -= qsz;
+ }
+swap:
+ ii = qsz;
+ do {
+ c = *i;
+ *i++ = *jj;
+ *jj++ = c;
+ } while (--ii);
+ i = tmp;
+ }
+ /*
+ * Look at sizes of the two partitions, do the smaller
+ * one first by recursion, then do the larger one by
+ * making sure lo is its size, base and max are update
+ * correctly, and branching back. But only repeat
+ * (recursively or by branching) if the partition is
+ * of at least size THRESH.
+ */
+ i = (j = mid) + qsz;
+ if ((lo = j - base) <= (hi = max - i)) {
+ if (lo >= thresh)
+ qst(base, j);
+ base = i;
+ lo = hi;
+ } else {
+ if (hi >= thresh)
+ qst(i, max);
+ max = j;
+ }
+ } while (lo >= thresh);
+
+ return(0);
+}
+
+/*
+ * qsort:
+ * First, set up some global parameters for qst to share. Then, quicksort
+ * with qst(), and then a cleanup insertion sort ourselves. Sound simple?
+ * It's not...
+ */
+
+int rmac_qsort(char *base, int n, int size, int (*compar)()) {
+ register char c, *i, *j, *lo, *hi;
+ char *min, *max;
+
+ if (n <= 1)
+ return(0);
+ qsz = size;
+ qcmp = compar;
+ thresh = qsz * THRESH;
+ mthresh = qsz * MTHRESH;
+ max = base + n * qsz;
+ if (n >= THRESH) {
+ qst(base, max);
+ hi = base + thresh;
+ } else {
+ hi = max;
+ }
+ /*
+ * First put smallest element, which must be in the first THRESH, in
+ * the first position as a sentinel. This is done just by searching
+ * the first THRESH elements (or the first n if n < THRESH), finding
+ * the min, and swapping it into the first position.
+ */
+ for (j = lo = base; (lo += qsz) < hi; )
+ if (qcmp(j, lo) > 0)
+ j = lo;
+ if (j != base) {
+ /* swap j into place */
+ for (i = base, hi = base + qsz; i < hi; ) {
+ c = *j;
+ *j++ = *i;
+ *i++ = c;
+ }
+ }
+ /*
+ * With our sentinel in place, we now run the following hyper-fast
+ * insertion sort. For each remaining element, min, from [1] to [n-1],
+ * set hi to the index of the element AFTER which this one goes.
+ * Then, do the standard insertion sort shift on a character at a time
+ * basis for each element in the frob.
+ */
+ for (min = base; (hi = min += qsz) < max; ) {
+ while (qcmp(hi -= qsz, min) > 0)
+ /* void */;
+ if ((hi += qsz) != min) {
+ for (lo = min + qsz; --lo >= min; ) {
+ c = *lo;
+ for (i = j = lo; (j -= qsz) >= hi; i = j)
+ *i = *j;
+ *i = c;
+ }
+ }
+ }
+ return(0);
+}
+
+//
+// --- Allocate memory; Panic and Quit if we Run Out -----------------------------------------------
+//
+
+char * amem(LONG amount)
+{
+ char * p;
+
+ if (amount & 1) // Keep word alignment
+ ++amount;
+
+ if (amount < A_THRESH)
+ { // Honor *small* request
+ if (a_amount < amount)
+ {
+ a_ptr = amem(A_AMOUNT);
+ a_amount = A_AMOUNT;
+ }
+
+ p = a_ptr;
+ a_ptr += amount;
+ a_amount -= amount;
+ }
+ else
+ {
+ amemtot += amount; // Bump total alloc
+ p = (char *)malloc(amount); // Get memory from malloc
+
+ if ((LONG)p == (LONG)NULL)
+ fatal("memory exhausted");
+
+ memset(p, 0, amount);
+ }
+
+ return p;
+}
+
+//
+// --- Copy stuff around, return pointer to dest+count+1 (doesn't handle overlap) ------------------
+//
+
+char * copy(char * dest, char * src, LONG count)
+{
+ while (count--)
+ *dest++ = *src++;
+
+ return dest;
+}
+
+//
+// --- Clear a region of memory --------------------------------------------------------------------
+//
+
+void clear(char *dest, LONG count)
+{
+ while(count--)
+ *dest++ = 0;
+}
+
+//
+// --- Check to see if the string is a keyword. Returns -1, or a value from the 'accept[]' table ---
+//
+
+int kmatch(char * p, int * base, int * check, int * tab, int * accept)
+{
+ int state;
+ int j;
+
+ for(state=0; state>=0;)
+ {
+ j = base[state] + (int)tolowertab[*p];
+
+ if (check[j] != state)
+ { // Reject, character doesn't match
+ state = -1; // No match
+ break;
+ }
+
+ if (!*++p)
+ { // Must accept or reject at EOS
+ state = accept[j]; // (-1 on no terminal match)
+ break;
+ }
+
+ state = tab[j];
+ }
+
+ return state;
+}
+
+//
+// --- Auto-even a section -------------------------------------------------------------------------
+//
+
+void autoeven(int sect)
+{
+ switchsect(sect);
+ d_even();
+ savsect();
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Manipulate file extension.
+// `name' must be large enough to hold any possible filename.
+// If `stripp' is nonzero, any old extension is removed.
+// Then, if the file does not already have an extension,
+// `extension' is appended to the filename.
+// -------------------------------------------------------------------------------------------------
+//
+
+char *fext(char *name, char *extension, int stripp) {
+ char *s, *beg; // String pointers
+
+ // Find beginning of "real" name
+ beg = name + strlen(name) - 1;
+ for(; beg > name; --beg) {
+ if(*beg == SLASHCHAR) {
+ ++beg;
+ break;
+ }
+ }
+
+ if(stripp) { // Clobber any old extension
+ for(s = beg; *s && *s != '.'; ++s)
+ ;
+ *s = '\0';
+ }
+
+ for(s = beg; *s != '.'; ++s) {
+ if(!*s) { // Append the new extension
+ strcat(beg, extension);
+ break;
+ }
+ }
+
+ return(name);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Return `item'nth element of semicolon-seperated pathnames specified in the enviroment string `s'.
+// Copy the pathname to `buf'. Return 0 if the `item'nth path doesn't exist.
+//
+// [`item' ranges from 0 to N-1, where N = #elements in search path]
+// -------------------------------------------------------------------------------------------------
+//
+
+int nthpath(char * env_var, int itemno, char * buf)
+{
+ char * s = searchpath;
+
+ if (s == NULL)
+ s = getenv(env_var);
+
+ if (s == NULL)
+ return 0;
+
+ while (itemno--)
+ while (*s != EOS && *s++ != ';')
+ ;
+
+ if (*s == EOS)
+ return 0;
+
+ while (*s != EOS && *s != ';')
+ *buf++ = *s++;
+
+ *buf++ = EOS;
+
+ return 1;
+}
+
+//
+// --- Display Command Line Help -----------------------------------------------
+//
+
+void display_help(void)
+{
+ printf("Usage:\n");
+ printf(" %s [options] srcfile\n", cmdlnexec);
+ printf("\n");
+ printf("Options:\n");
+ printf(" -? or -h display usage information\n");
+ printf(" -dsymbol[=value] define symbol\n");
+ printf(" -e[errorfile] send error messages to file, not stdout\n");
+ printf(" -f[format] output object file format\n");
+ printf(" b: BSD (use this for Jaguar)\n");
+ printf(" -i[path] directory to search for include files\n");
+ printf(" -l[filename] create an output listing file\n");
+ printf(" -o file output file name\n");
+ printf(" -r[size] pad segments to boundary size specified\n");
+ printf(" w: word (2 bytes, default alignment)\n");
+ printf(" l: long (4 bytes)\n");
+ printf(" p: phrase (8 bytes)\n");
+ printf(" d: double phrase (16 bytes)\n");
+ printf(" q: quad phrase (32 bytes)\n");
+ printf(" -s warn about possible short branches\n");
+ printf(" -u force referenced and undefined symbols global\n");
+ printf(" -v set verbose mode\n");
+ printf(" -y[pagelen] set page line length (default: 61)\n");
+ printf("\n");
+}
+
+//
+// --- Display Version Information ---------------------------------------------
+//
+
+void display_version(void)
+{
+ printf("\nReboot's Macro Assembler for Atari Jaguar\n");
+ printf("Copyright (C) 199x Landon Dyer, 2011 Reboot\n");
+ printf("V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
+}
+
+//
+// --- Process Command Line Arguments and do an Assembly -------------------------------------------
+//
+
+int process(int argc, char **argv) {
+ int argno; // Argument number
+ SYM *sy; // Pointer to a symbol record
+ char *s; // String pointer
+ int fd; // File descriptor
+ char fnbuf[FNSIZ]; // Filename buffer
+ int i; // Iterator
+
+ errcnt = 0; // Initialise error count
+ listing = 0; // Initialise listing level
+ list_flag = 0; // Initialise listing flag
+ verb_flag = perm_verb_flag; // Initialise verbose flag
+ as68_flag = 0; // Initialise as68 kludge mode
+ glob_flag = 0; // Initialise .globl flag
+ sbra_flag = 0; // Initialise short branch flag
+ debug = 0; // Initialise debug flag
+ searchpath = NULL; // Initialise search path
+ objfname = NULL; // Initialise object filename
+ list_fname = NULL; // Initialise listing filename
+ err_fname = NULL; // Initialise error filename
+ obj_format = BSD; // Initialise object format
+ firstfname = NULL; // Initialise first filename
+ err_fd = ERROUT; // Initialise error file descriptor
+ err_flag = 0; // Initialise error flag
+ rgpu = 0; // Initialise GPU assembly flag
+ rdsp = 0; // Initialise DSP assembly flag
+ lsym_flag = 1; // Include local symbols in object file
+ regbank = BANK_N; // No RISC register bank specified
+ orgactive = 0; // Not in RISC org section
+ orgwarning = 0; // No ORG warning issued
+ a_amount = 0;
+ segpadsize = 2; // Initialise segment padding size
+ in_main = 0;
+
+ // Initialise modules
+ init_sym(); // Symbol table
+ init_token(); // Tokenizer
+ init_procln(); // Line processor
+ init_expr(); // Expression analyzer
+ init_sect(); // Section manager / code generator
+ init_mark(); // Mark tape-recorder
+ init_macro(); // Macro processor
+ init_list(); // Listing generator
+
+ // Process command line arguments and assemble source files
+ for(argno = 0; argno < argc; ++argno) {
+ if(*argv[argno] == '-') {
+ switch(argv[argno][1]) {
+ case 'd': // Define symbol
+ case 'D':
+ for(s = argv[argno] + 2; *s != EOS;) {
+ if(*s++ == '=') {
+ s[-1] = EOS;
+ break;
+ }
+ }
+ if(argv[argno][2] == EOS) {
+ printf("-d: empty symbol\n");
+ ++errcnt;
+ return(errcnt);
+ }
+ sy = lookup(argv[argno] + 2, 0, 0);
+ if(sy == NULL) {
+ sy = newsym(argv[argno] + 2, LABEL, 0);
+ sy->svalue = 0;
+ }
+ sy->sattr = DEFINED | EQUATED | ABS;
+ if(*s)
+ sy->svalue = (VALUE)atoi(s);
+ else
+ sy->svalue = 0;
+ break;
+ case 'e': // Redirect error message output
+ case 'E':
+ err_fname = argv[argno] + 2;
+ break;
+ case 'f': // -f<format>
+ case 'F':
+ switch(argv[argno][2]) {
+ case EOS:
+ case 'b': // -fb = BSD (Jaguar Recommended)
+ case 'B':
+ obj_format = BSD;
+ break;
+ default:
+ printf("-f: unknown object format specified\n");
+ ++errcnt;
+ return(errcnt);
+ }
+ break;
+ case 'g': // Debugging flag
+ case 'G':
+ printf("Debugging flag (-g) not yet implemented\n");
+ break;
+ case 'i': // Set directory search path
+ case 'I':
+ searchpath = argv[argno] + 2;
+ break;
+ case 'l': // Produce listing file
+ case 'L':
+ list_fname = argv[argno] + 2;
+ listing = 1;
+ list_flag = 1;
+ ++lnsave;
+ break;
+ case 'o': // Direct object file output
+ case 'O':
+ if(argv[argno][2] != EOS) objfname = argv[argno] + 2;
+ else {
+ if(++argno >= argc) {
+ printf("Missing argument to -o");
+ ++errcnt;
+ return(errcnt);
+ }
+ objfname = argv[argno];
+ }
+ break;
+ case 'r': // Pad seg to requested boundary size
+ case 'R':
+ switch(argv[argno][2]) {
+ case 'w': case 'W': segpadsize = 2; break;
+ case 'l': case 'L': segpadsize = 4; break;
+ case 'p': case 'P': segpadsize = 8; break;
+ case 'd': case 'D': segpadsize = 16; break;
+ case 'q': case 'Q': segpadsize = 32; break;
+ default: segpadsize = 2; break; // Effective autoeven();
+ }
+ break;
+ case 's': // Warn about possible short branches
+ case 'S':
+ sbra_flag = 1;
+ break;
+ case 'u': // Make undefined symbols .globl
+ case 'U':
+ glob_flag = 1;
+ break;
+ case 'v': // Verbose flag
+ case 'V':
+ verb_flag++;
+ if(verb_flag > 1) display_version();
+ break;
+ case 'x': // Turn on debugging
+ case 'X':
+ debug = 1;
+ printf("~ Debugging ON\n");
+ break;
+ case 'y': // -y<pagelen>
+ case 'Y':
+ pagelen = atoi(argv[argno] + 2);
+ if(pagelen < 10) {
+ printf("-y: bad page length\n");
+ ++errcnt;
+ return(errcnt);
+ }
+ break;
+ case EOS: // Input is stdin
+ if(firstfname == NULL) // Kludge first filename
+ firstfname = defname;
+ include(0, "(stdin)");
+ assemble();
+ break;
+ case 'h': // Display command line usage
+ case 'H':
+ case '?':
+ display_version();
+ display_help();
+ ++errcnt;
+ break;
+ default:
+ display_version();
+ printf("Unknown switch: %s\n\n", argv[argno]);
+ display_help();
+ ++errcnt;
+ break;
+ }
+ } else {
+ // Record first filename.
+ if(firstfname == NULL)
+ firstfname = argv[argno];
+ strcpy(fnbuf, argv[argno]);
+ fext(fnbuf, ".s", 0);
+ fd = open(fnbuf, 0);
+ if(fd < 0) {
+ printf("Cannot open: %s\n", fnbuf);
+ ++errcnt;
+ continue;
+ }
+ include(fd, fnbuf);
+ assemble();
+ }
+ }
+
+ // Wind-up processing;
+ // o save current section (no more code generation)
+ // o do auto-even of all sections (or boundary alignment as requested through '-r')
+ // o determine name of object file:
+ // - "foo.o" for linkable output;
+ // - "foo.prg" for GEMDOS executable (-p flag).
+ savsect();
+ for(i = TEXT; i <= BSS; i <<= 1) {
+ switchsect(i);
+ switch(segpadsize) {
+ case 2: d_even(); break;
+ case 4: d_long(); break;
+ case 8: d_phrase(); break;
+ case 16: d_dphrase(); break;
+ case 32: d_qphrase(); break;
+ }
+ savsect();
+ }
+
+ if(objfname == NULL) {
+ if(firstfname == NULL)
+ firstfname = defname;
+ strcpy(fnbuf, firstfname);
+ //fext(fnbuf, prg_flag ? ".prg" : ".o", 1);
+ fext(fnbuf, ".o", 1);
+ objfname = fnbuf;
+ }
+
+ // With one pass finished, go back and:
+ // (1) run through all the fixups and resolve forward references;
+ // (1.5) ensure that remaining fixups can be handled by the linker
+ // (`lo68' format, extended (postfix) format....)
+ // (2) generate the output file image and symbol table;
+ // (3) generate relocation information from left-over fixups.
+ fixups(); // Do all fixups
+ stopmark(); // Stop mark tape-recorder
+ if(errcnt == 0) {
+ if((fd = open(objfname, _OPEN_FLAGS, _PERM_MODE)) < 0)
+ cantcreat(objfname);
+ if(verb_flag) {
+ s = "object";
+ printf("[Writing %s file: %s]\n", s, objfname);
+ }
+ object((WORD)fd);
+ close(fd);
+ if(errcnt != 0)
+ unlink(objfname);
+ }
+
+ if(list_flag) {
+ if(verb_flag) printf("[Wrapping-up listing file]\n");
+ listing = 1;
+ symtable();
+ close(list_fd);
+ }
+
+ if(err_flag)
+ close(err_fd);
+
+ DEBUG dump_everything();
+
+ return(errcnt);
+}
+
+//
+// --- Interactive Mode ----------------------------------------------------------------------------
+//
+
+void interactive(void)
+{
+ char * s; // String pointer for banner
+ char ln[LNSIZ]; // Input line
+ char * argv[MAXARGV]; // Argument values
+ int argcnt; // Argument count
+
+ // As there is no command line, print a copyright message and prompt for command line
+ s = "*****************************************************\n";
+ printf("\n%s* RMAC - Reboot's Macro Assembler for Atari Jaguar *\n", s);
+ printf("* Copyright (C) 199x Landon Dyer, 2011 Reboot *\n");
+ printf("* Version %01i.%01i.%01i Platform: %-9s *\n",MAJOR,MINOR,PATCH,PLATFORM);
+ printf("* ------------------------------------------------- *\n");
+ printf("* INTERACTIVE MODE *\n%s\n", s);
+
+ perm_verb_flag = 1; // Enter permanent verbose mode
+
+ // Handle commandlines until EOF or we get an empty one
+ for(;;)
+ {
+ loop:
+ printf("* ");
+ fflush(stdout); // Make prompt visible
+
+ if (gets(ln) == NULL || !*ln) // Get input line
+ break;
+
+ argcnt = 0; // Process input line
+ s = ln;
+
+ while (*s)
+ {
+ if (isspace(*s))
+ { // Skip whitespace
+ ++s;
+ }
+ else
+ {
+ if (argcnt >= MAXARGV)
+ {
+ printf("Too many arguments\n");
+ goto loop;
+ }
+
+ argv[argcnt++] = s;
+
+ while (*s && !isspace(*s))
+ ++s;
+
+ if (isspace(*s))
+ *s++ = EOS;
+ }
+ }
+
+ if (argcnt == 0) // Exit if no arguments
+ break;
+
+ process(argcnt, argv); // Process arguments
+
+ if (errcnt)
+ printf("%d assembly error%s\n", errcnt, (errcnt > 1) ? "s" : "");
+ }
+}
+
+//
+// --- Determine Processor Endianess ---------------------------------------------------------------
+//
+
+int get_endianess(void)
+{
+ int i = 1;
+ char * p = (char *)&i;
+
+ if (p[0] == 1)
+ return 0;
+
+ return 1;
+}
+
+//
+// --- Application Entry Point; Handle the Command Line --------------------------------------------
+//
+
+int main(int argc, char ** argv)
+{
+ int status; // Status flag
+ int i;
+
+ perm_verb_flag = 0; // Clobber "permanent" verbose flag
+ cmdlnexec = argv[0]; // Obtain executable name
+
+ endian = get_endianess(); // Get processor endianess
+
+ for(i=0; i<MAXFWDJUMPS; i++)
+ fwdjump[i] = 0;
+
+ if (argc > 1)
+ { // Full command line passed
+ status = process(argc - 1, argv + 1);
+ }
+ else
+ { // Interactive mode
+ status = 0;
+ interactive();
+ }
+
+ return status;
+}
--- /dev/null
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC.H - Main Application Code
+// Copyright (C) 199x Landon Dyer, 2011 Reboot & Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+//
+
+#ifndef __RMAC_H__
+#define __RMAC_H__
+
+//
+// TARGET SPECIFIC BUILD SETTINGS
+//
+
+#ifdef WIN32
+#define PLATFORM "Win32" // Release platform - windows
+#define _OPEN_FLAGS _O_TRUNC|_O_CREAT|_O_BINARY|_O_RDWR
+#define _OPEN_INC _O_RDONLY|_O_BINARY
+#define _PERM_MODE _S_IREAD|_S_IWRITE
+#ifdef _MSC_VER
+ #if _MSC_VER > 1000
+ #pragma warning(disable:4996)
+ #endif
+#endif
+#include <io.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#else
+#ifdef __GCCUNIX__
+#define PLATFORM "OSX/Linux" // Release platform - mac OS-X or linux
+#define _OPEN_FLAGS O_TRUNC|O_CREAT|O_RDWR
+#define _OPEN_INC O_RDONLY
+#define _PERM_MODE S_IREAD|S_IWRITE
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#else
+#define PLATFORM "Unknown" // Release platform - not specified
+#define _OPEN_FLAGS O_TRUNC|O_CREAT|O_RDWR
+#define _OPEN_INC O_RDONLY
+#define _PERM_MODE S_IREAD|S_IWRITE
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+#endif
+
+
+
+#define BYTE unsigned char
+#define WORD unsigned short
+#define LONG unsigned long
+#define VOID void
+
+#define ERROR (-1) // Generic error return
+#define EOS '\0' // End of string
+#define SPACE ' ' // Ascii space
+#define SLASHCHAR '/'
+#define SLASHSTRING "/"
+#define VALUE LONG // Assembler value
+#define TOKEN LONG // Assembler token
+#define FNSIZ 128 // Maximum size of a filename
+#define OK 0 // OK return
+#define DEBUG if(debug) // Debug conditional
+#define MAXARGV 100 // Maximum number of commandline args
+#define STDOUT 1 // Standard output
+#define ERROUT 2 // Error output
+#define CREATMASK 0
+
+// (Normally) non-printable tokens
+#define COLON ':' // : (grumble: GNUmacs hates ':')
+#define CONST 'a' // CONST <value>
+#define ACONST 'A' // ACONST <value> <attrib>
+#define STRING 'b' // STRING <address>
+#define SYMBOL 'c' // SYMBOL <address>
+#define EOL 'e' // End of line
+#define TKEOF 'f' // End of file (or macro)
+#define DEQUALS 'g' // ==
+#define SET 149 // set
+#define REG 'R' // reg
+#define EQUREG 148 // equreg
+#define CCDEF 183 // ccdef
+#define DCOLON 'h' // ::
+#define GE 'i' // >=
+#define LE 'j' // <=
+#define NE 'k' // <> or !=
+#define SHR 'l' // >>
+#define SHL 'm' // <<
+#define UNMINUS 'n' // Unary '-'
+#define DOTB 'B' // .b or .B or .s or .S
+#define DOTW 'W' // .w or .W
+#define DOTL 'L' // .l or .L
+#define DOTI 'I' // .i or .I
+#define ENDEXPR 'E' // End of expression
+
+// Object code formats
+#define ALCYON 0 // Alcyon/DRI C object format
+#define MWC 1 // Mark Williams object format
+#define BSD 2 // BSD object format
+
+// Symbols
+#define SYM struct _sym
+SYM
+{
+ SYM *snext; // * -> Next symbol on hash-chain
+ SYM *sorder; // * -> Next sym in order of refrence
+ SYM *sdecl; // * -> Next sym in order of decleration
+ BYTE stype; // Symbol type
+ WORD sattr; // Attribute bits
+ LONG sattre; // Extended attribute bits
+ WORD senv; // Enviroment number
+ LONG svalue; // Symbol value
+ char *sname; // * -> Symbol's print-name
+};
+
+// Pointer type that can point to (almost) anything
+#define PTR union _ptr
+PTR
+{
+ char *cp; // Char
+ WORD *wp; // WORD
+ LONG *lp; // LONG
+ LONG lw; // LONG
+ SYM **sy; // SYM
+ TOKEN *tk; // TOKEN
+};
+
+// Symbol spaces
+#define LABEL 0 // User-defined symbol
+#define MACRO 1 // Macro definition
+#define MACARG 2 // Macro argument
+#define SY_UNDEF -1 // Undefined (lookup never matches it)
+
+// Symbol and expression attributes
+#define DEFINED 0x8000 // Symbol has been defined
+#define GLOBAL 0x4000 // Symbol has been .GLOBL'd
+#define COMMON 0x2000 // Symbol has been .COMM'd
+#define REFERENCED 0x1000 // Symbol has been referenced
+#define EQUATED 0x0800 // Symbol was equated
+#define SDECLLIST 0x0400 // Symbol is on 'sdecl'-order list
+
+// Expression spaces, ORed with symbol and expression attributes above
+#define ABS 0x0000 // In absolute space
+#define TEXT 0x0001 // Relative to text
+#define DATA 0x0002 // Relative to data
+#define BSS 0x0004 // Relative to BSS
+//#define M6502 0x0008 // 6502/microprocessor (absolute)
+#define TDB (TEXT|DATA|BSS) // Mask for text+data+bss
+
+// Sizes
+#define SIZB 0x0001 // .b
+#define SIZW 0x0002 // .w
+#define SIZL 0x0004 // .l
+#define SIZN 0x0008 // no .(size) specifier
+
+// RISC register bank definitions (used in extended symbol attributes also)
+#define BANK_N 0x0000 // No register bank specified
+#define BANK_0 0x0001 // Register bank zero specified
+#define BANK_1 0x0002 // Register bank one specified
+#define EQUATEDREG 0x0008 // Equated register symbol
+#define UNDEF_EQUR 0x0010
+#define EQUATEDCC 0x0020
+#define UNDEF_CC 0x0040
+
+#define RISCSYM 0x00010000
+
+// Globals, externals etc
+extern int verb_flag;
+extern int debug;
+extern int rgpu, rdsp;
+extern int err_flag;
+extern int err_fd;
+extern int regbank;
+extern char *firstfname;
+extern int list_fd;
+extern int as68_flag;
+extern int list_flag;
+extern int glob_flag;
+extern int lsym_flag;
+extern int sbra_flag;
+extern int obj_format;
+extern LONG amemtot;
+extern int in_main;
+
+// Prototypes
+void init_sym(void);
+SYM *lookup(char *, int, int);
+SYM *newsym(char *, int, int);
+char *fext(char *, char *, int);
+void cantcreat(char *);
+int kmatch(char *, int *, int *, int *, int *);
+void autoeven(int);
+int nthpath(char *, int, char *);
+void clear(char *, LONG);
+char *copy(char *, char *, LONG);
+int rmac_qsort(char *, int, int, int (*)());
+char *amem(LONG);
+
+#endif // __RMAC_H__
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// SECT.C - Code Generation, Fixups and Section Management
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "sect.h"
+#include "error.h"
+#include "mach.h"
+#include "token.h"
+#include "mark.h"
+#include "expr.h"
+#include "symbol.h"
+#include "risca.h"
+#include "listing.h"
+
+// Section descriptors
+SECT sect[NSECTS]; // All sections...
+int cursect; // Current section number
+
+// These are copied from the section descriptor, the current code chunk descriptor and the current
+// fixup chunk descriptor when a switch is made into a section. They are copied back to the
+// descriptors when the section is left.
+WORD scattr; // Section attributes
+LONG sloc; // Current loc in section
+
+CHUNK *scode; // Current (last) code chunk
+LONG challoc; // #bytes alloc'd to code chunk
+LONG ch_size; // #bytes used in code chunk
+char *chptr; // Deposit point in code chunk buffer
+
+CHUNK *sfix; // Current (last) fixup chunk
+LONG fchalloc; // #bytes alloc'd to fixup chunk
+LONG fchsize; // #bytes used in fixup chunk
+PTR fchptr; // Deposit point in fixup chunk buffer
+
+unsigned fwdjump[MAXFWDJUMPS]; // forward jump check table
+unsigned fwindex = 0; // forward jump index
+
+// Return a size (SIZB, SIZW, SIZL) or 0, depending on what kind of fixup is associated
+// with a location.
+static char fusiztab[] = {
+ 0, // FU_QUICK
+ 1, // FU_BYTE
+ 2, // FU_WORD
+ 2, // FU_WBYTE
+ 4, // FU_LONG
+ 1, // FU_BBRA
+ 0, // (unused)
+ 1, // FU_6BRA
+};
+
+// Offset to REAL fixup location
+static char fusizoffs[] = {
+ 0, // FU_QUICK
+ 0, // FU_BYTE
+ 0, // FU_WORD
+ 1, // FU_WBYTE
+ 0, // FU_LONG
+ 1, // FU_BBRA
+ 0, // (unused)
+ 0, // FU_6BRA
+};
+
+//
+// --- Make a New (Clean) Section ------------------------------------------------------------------
+//
+
+void mksect(int sno, WORD attr) {
+ SECT *p; // Section pointer
+
+ p = §[sno];
+ p->scattr = attr;
+ p->sloc = 0;
+ p->scode = p->sfcode = NULL;
+ p->sfix = p->sffix = NULL;
+}
+
+//
+// --- Switch to Another Section (Copy Section & Chunk Descriptors to Global Vars for Fast Access) -
+//
+
+void switchsect(int sno) {
+ SECT *p; // Section pointer
+ CHUNK *cp; // Chunk pointer
+
+ cursect = sno;
+ p = §[sno];
+
+ scattr = p->scattr; // Copy section vars
+ sloc = p->sloc;
+ scode = p->scode;
+ sfix = p->sfix;
+
+ if((cp = scode) != NULL) { // Copy code chunk vars
+ challoc = cp->challoc;
+ ch_size = cp->ch_size;
+ chptr = cp->chptr + ch_size;
+ } else challoc = ch_size = 0;
+
+ if((cp = sfix) != NULL) { // Copy fixup chunk vars
+ fchalloc = cp->challoc;
+ fchsize = cp->ch_size;
+ fchptr.cp = cp->chptr + fchsize;
+ } else fchalloc = fchsize = 0;
+}
+
+//
+// --- Save Current Section ------------------------------------------------------------------------
+//
+
+void savsect(void) {
+ SECT *p;
+
+ p = §[cursect];
+
+ p->scattr = scattr; // Bailout section vars
+ p->sloc = sloc;
+
+ if(scode != NULL) // Bailout code chunk
+ scode->ch_size = ch_size;
+
+ if(sfix != NULL) // Bailout fixup chunk
+ sfix->ch_size = fchsize;
+}
+
+//
+// --- Initialize Sections; Setup initial ABS, TEXT, DATA and BSS sections -------------------------
+//
+
+void init_sect(void) {
+ int i; // Iterator
+
+ // Cleanup all sections
+ for(i = 0; i < NSECTS; ++i)
+ mksect(i, 0);
+
+ // Construct default sections, make TEXT the current section
+ mksect(ABS, SUSED|SABS|SBSS); // ABS
+ mksect(TEXT, SUSED|TEXT ); // TEXT
+ mksect(DATA, SUSED|DATA ); // DATA
+ mksect(BSS, SUSED|BSS |SBSS); // BSS
+// mksect(M6502, SUSED|TEXT ); // 6502 code section
+
+ switchsect(TEXT); // Switch to TEXT for starters
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Test to see if a location has a fixup sic'd on it. This is used by the listing
+// generator to print 'xx's instead of '00's for forward references
+// -------------------------------------------------------------------------------------------------
+//
+
+int fixtest(int sno, LONG loc) {
+ CHUNK *ch;
+ PTR fup;
+ char *fuend;
+ WORD w;
+ LONG xloc;
+
+ stopmark(); // Force update to sect[] variables
+
+ // Hairy, ugly linear search for a mark on our location;
+ // the speed doesn't matter, since this is only done when generating a listing, which is SLOW.
+ for(ch = sect[sno].sffix; ch != NULL; ch = ch->chnext) {
+ fup.cp = (char *)ch->chptr;
+ fuend = fup.cp + ch->ch_size;
+
+ while(fup.cp < fuend) {
+ w = *fup.wp++;
+ xloc = *fup.lp++ + (int)fusizoffs[w & FUMASK];
+ fup.wp += 2;
+
+ if(xloc == loc)
+ return((int)fusiztab[w & FUMASK]);
+
+ if(w & FU_EXPR) {
+ w = *fup.wp++;
+ fup.lp += w;
+ } else ++fup.lp;
+ }
+ }
+
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Check that there are at least `amt' bytes left in the current chunk. If there are not,
+// allocate another chunk of at least `amt' bytes (and probably more).
+//
+// If `amt' is zero, ensure there are at least CH_THRESHOLD bytes, likewise.
+// -------------------------------------------------------------------------------------------------
+//
+
+int chcheck(LONG amt) {
+ CHUNK *cp;
+ SECT *p;
+
+ if(scattr & SBSS) return(0); // If in BSS section, forget it
+
+ if(!amt) amt = CH_THRESHOLD;
+
+ if((int)(challoc - ch_size) >= (int)amt)
+ return(0);
+
+ if(amt < CH_CODE_SIZE) amt = CH_CODE_SIZE;
+ p = §[cursect];
+ cp = (CHUNK *)amem((long)(sizeof(CHUNK) + amt));
+ if(scode == NULL) { // First chunk in section
+ cp->chprev = NULL;
+ p->sfcode = cp;
+ } else { // Add chunk to other chunks
+ cp->chprev = scode;
+ scode->chnext = cp;
+ scode->ch_size = ch_size; // Save old chunk's globals
+ }
+
+ // Setup chunk and global vars
+ cp->chloc = sloc;
+ cp->chnext = NULL;
+ challoc = cp->challoc = amt;
+ ch_size = cp->ch_size = 0;
+ chptr = cp->chptr = ((char *)cp) + sizeof(CHUNK);
+ scode = p->scode = cp;
+
+ return(0);
+}
+
+//
+// --- Arrange for a fixup on a location -----------------------------------------------------------
+//
+
+int fixup(WORD attr, LONG loc, TOKEN *fexpr) {
+ LONG i;
+ LONG len = 0;
+ CHUNK *cp;
+ SECT *p;
+
+ // Compute length of expression (could be faster); determine if it's the single-symbol case;
+ // no expression if it's just a mark. This code assumes 16 bit WORDs and 32 bit LONGs
+ if(*fexpr == SYMBOL && fexpr[2] == ENDEXPR)
+ //if((attr & 0x0F00) == FU_JR) {
+ if((attr & 0x0200) == FU_JR) {
+ i = 18; // Just a single symbol
+ } else {
+ i = 14;
+ }
+ else {
+ attr |= FU_EXPR;
+ for(len = 0; fexpr[len] != ENDEXPR; ++len)
+ if(fexpr[len] == CONST || fexpr[len] == SYMBOL)
+ ++len;
+ ++len; // Add 1 for ENDEXPR
+ i = (len << 2) + 12;
+ }
+
+ // Maybe alloc another fixup chunk for this one to fit in
+ if((fchalloc - fchsize) < i) {
+ p = §[cursect];
+ cp = (CHUNK *)amem((long)(sizeof(CHUNK) + CH_FIXUP_SIZE));
+ if(sfix == NULL) { // First fixup chunk in section
+ cp->chprev = NULL;
+ p->sffix = cp;
+ } else { // Add to other chunks
+ cp->chprev = sfix;
+ sfix->chnext = cp;
+ sfix->ch_size = fchsize;
+ }
+
+ // Setup fixup chunk and its global vars
+ cp->chnext = NULL;
+ fchalloc = cp->challoc = CH_FIXUP_SIZE;
+ fchsize = cp->ch_size = 0;
+ fchptr.cp = cp->chptr = ((char *)cp) + sizeof(CHUNK);
+ sfix = p->sfix = cp;
+ }
+
+ // Record fixup type, fixup location, and the file number and line number the fixup is
+ // located at.
+ *fchptr.wp++ = attr;
+ *fchptr.lp++ = loc;
+ *fchptr.wp++ = cfileno;
+ *fchptr.wp++ = (WORD)curlineno;
+ // Store postfix expression or pointer to a single symbol, or nothing for a mark.
+ if(attr & FU_EXPR) {
+ *fchptr.wp++ = (WORD)len;
+ while(len--)
+ *fchptr.lp++ = (LONG)*fexpr++;
+ } else {
+ *fchptr.lp++ = (LONG)fexpr[1];
+ }
+
+ //if((attr & 0x0F00) == FU_JR) {
+ if((attr & 0x0200) == FU_JR) {
+ if(orgactive) *fchptr.lp++ = orgaddr;
+ else *fchptr.lp++ = 0x00000000;
+ }
+
+ fchsize += i;
+
+ return(0);
+}
+
+//
+// --- Resolve all Fixups --------------------------------------------------------------------------
+//
+
+int fixups(void) {
+ unsigned i; // Iterator
+ char buf[EBUFSIZ];
+
+ if(glob_flag) // Make undefined symbols GLOBL
+ syg_fix();
+ resfix(TEXT);
+ resfix(DATA);
+
+ // We need to do a final check of forward 'jump' destination addresses that are external
+ for(i = 0; i < MAXFWDJUMPS; i++) {
+ if(fwdjump[i]) {
+ err_setup();
+ sprintf(buf, "* \'jump\' at $%08X - destination address is external to this source file and "
+ "cannot have its aligment validated", fwdjump[i]);
+ if(listing > 0) ship_ln(buf);
+ if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
+ else printf("%s\n", buf);
+ }
+ }
+
+ return(0);
+}
+
+//
+// --- Resolve Fixups in a Section -----------------------------------------------------------------
+//
+
+int resfix(int sno) {
+ SECT *sc; // Section
+ CHUNK *ch;
+ PTR fup; // Current fixup
+ WORD *fuend; // End of last fixup (in this chunk)
+ CHUNK *cch; // Cached chunk for target
+ WORD w; // Fixup word (type+modes+flags)
+ char *locp; // Location to fix (in cached chunk)
+ LONG loc; // Location to fixup
+ VALUE eval; // Expression value
+ WORD eattr; // Expression attrib
+ SYM *esym; // External symbol involved in expr
+ SYM *sy; // (Temp) pointer to a symbol
+ WORD i; // (Temp) word
+ WORD tdb; // eattr & TDB
+ LONG oaddr;
+ int reg2;
+ WORD flags;
+ unsigned page_jump = 0;
+ unsigned address = 0;
+ unsigned j; // iterator
+ char buf[EBUFSIZ];
+
+ sc = §[sno];
+ ch = sc->sffix;
+
+ if(ch == NULL)
+ return(0);
+
+ cch = sc->sfcode; // "cache" first chunk
+ if(cch == NULL) // Can't fixup a sect with nothing in it
+ return(0);
+
+ do {
+ fup.cp = ch->chptr; // fup -> start of chunk
+ fuend = (WORD *)(fup.cp + ch->ch_size); // fuend -> end of chunk
+ while(fup.wp < fuend) {
+ w = *fup.wp++;
+ loc = *fup.lp++;
+ cfileno = *fup.wp++;
+ curlineno = (int)*fup.wp++;
+
+ esym = NULL;
+ // Search for chunk containing location to fix up; compute a pointer to the location
+ // (in the chunk). Often we will find the fixup is in the "cached" chunk, so the
+ // linear-search is seldom executed.
+ if(loc < cch->chloc || loc >= (cch->chloc + cch->ch_size)) {
+ for(cch = sc->sfcode; cch != NULL; cch = cch->chnext)
+ if(loc >= cch->chloc && loc < (cch->chloc + cch->ch_size))
+ break;
+ if(cch == NULL) {
+ interror(7); // Fixup (loc) out of range
+ // NOTREACHED
+ }
+ }
+ locp = cch->chptr + (loc - cch->chloc);
+
+ eattr = 0;
+
+ // Compute expression/symbol value and attribs
+ if(w & FU_EXPR) { // Complex expression
+ i = *fup.wp++;
+ if(evexpr(fup.tk, &eval, &eattr, &esym) != OK) {
+ fup.lp += i;
+ continue;
+ }
+ fup.lp += i;
+ } else { // Simple symbol
+ sy = *fup.sy++;
+ eattr = sy->sattr;
+ if(eattr & DEFINED)
+ eval = sy->svalue;
+ else eval = 0;
+
+ if((eattr & (GLOBAL|DEFINED)) == GLOBAL)
+ esym = sy;
+ }
+ tdb = (WORD)(eattr & TDB);
+ // If the expression is undefined and no external symbol is involved, then it's an error.
+ if(!(eattr & DEFINED) && esym == NULL) {
+ error(undef_error);
+ continue;
+ }
+
+
+ if(((w & 0x0F00) == FU_MOVEI) && esym)
+ esym->sattre |= RISCSYM;
+
+ // Do the fixup
+ //
+ // If a PC-relative fixup is undefined, its value is *not* subtracted from the location
+ // (that will happen in the linker when the external reference is resolved).
+ //
+ // MWC expects PC-relative things to have the LOC subtracted from the value, if the
+ // value is external (that is, undefined at this point).
+ //
+ // PC-relative fixups must be DEFINED and either in the same section (whereupon the
+ // subtraction takes place) or ABS (with no subtract).
+ if(w & FU_PCREL) {
+ if(eattr & DEFINED) {
+ if(tdb == sno) eval -= (VALUE)loc;
+ else if(tdb) {
+ error("PC-relative expr across sections");
+ continue;
+ }
+
+ if(sbra_flag && (w & FU_LBRA) && (eval + 0x80 < 0x100))
+ warn("unoptimized short branch");
+ } else
+ if(obj_format == MWC) eval -= (VALUE)loc;
+
+ tdb = 0;
+ eattr &= ~TDB;
+ }
+
+ // Do fixup classes
+ switch((int)(w & FUMASK)) {
+ // FU_BBRA fixes up a one-byte branch offset.
+ case FU_BBRA:
+ if(!(eattr & DEFINED)) {
+ error("external short branch");
+ continue;
+ }
+ eval -= 2;
+ if(eval + 0x80 >= 0x100)
+ goto range;
+ if(eval == 0) {
+ error("illegal bra.s with zero offset");
+ continue;
+ }
+ *++locp = (char)eval;
+ break;
+ // Fixup one-byte value at locp + 1.
+ case FU_WBYTE:
+ ++locp;
+ // FALLTHROUGH
+ // Fixup one-byte forward references
+ case FU_BYTE:
+ if(!(eattr & DEFINED)) {
+ error("external byte reference");
+ continue;
+ }
+ if(tdb) {
+ error("non-absolute byte reference");
+ continue;
+ }
+ if((w & FU_PCREL) && eval + 0x80 >= 0x100) goto range;
+ if(w & FU_SEXT) {
+ if(eval + 0x100 >= 0x200) goto range;
+ } else
+ if(eval >= 0x100) goto range;
+
+ *locp = (char)eval;
+ break;
+ // Fixup WORD forward references;
+ // the word could be unaligned in the section buffer, so we have to be careful.
+ case FU_WORD:
+ if(((w & 0x0F00) == FU_JR) || ((w & 0x0F00) == FU_MJR)) {
+ oaddr = *fup.lp++;
+ if(oaddr) {
+ reg2 = (signed)((eval - (oaddr + 2)) / 2);// & 0x1F;
+ } else {
+ reg2 = (signed)((eval - (loc + 2)) / 2);// & 0x1F;
+ }
+ if((w & 0x0F00) == FU_MJR) {
+ // Main code destination alignment checking here for forward declared labels
+ address = (oaddr) ? oaddr : loc;
+ if(((address >= 0xF03000) && (address < 0xF04000) && (eval < 0xF03000)) ||
+ ((eval >= 0xF03000) && (eval < 0xF04000) && (address < 0xF03000)) ) {
+ warni("* \'jr\' at $%08X - cannot jump relative between "
+ "main memory and local gpu ram", address);
+ } else {
+ page_jump = (address & 0xFFFFFF00) - (eval & 0xFFFFFF00);
+ if(page_jump) {
+ // This jump is to a page outside of the current 256 byte page
+ if(eval % 4) {
+ warni("* \'jr\' at $%08X - destination address not aligned for long page jump, "
+ "insert a \'nop\' before the destination address", address);
+ }
+ } else {
+ // This jump is in the current 256 byte page
+ if((eval - 2) % 4) {
+ warni("* \'jr\' at $%08X - destination address not aligned for short page jump, "
+ "insert a \'nop\' before the destination address", address);
+ }
+ }
+ }
+ }
+ if((reg2 < -16) || (reg2 > 15)) {
+ error("relative jump out of range");
+ break;
+ }
+ *locp = (char)(*locp | ((reg2 >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((reg2 & 0x07) << 5));
+ break;
+ }
+ if((w & 0x0F00) == FU_NUM15) {
+ if(eval < -16 || eval > 15) {
+ error("constant out of range");
+ break;
+ }
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+ if((w & 0x0F00) == FU_NUM31) {
+ if(eval < 0 || eval > 31) {
+ error("constant out of range");
+ break;
+ }
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+ if((w & 0x0F00) == FU_NUM32) {
+ if(eval < 1 || eval > 32) {
+ error("constant out of range");
+ break;
+ }
+ if(w & FU_SUB32)
+ eval = (32 - eval);
+ eval = (eval == 32) ? 0 : eval;
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+ if((w & 0x0F00) == FU_REGONE) {
+ if(eval < 0 || eval > 31) {
+ error("register value out of range");
+ break;
+ }
+ *locp = (char)(*locp | ((eval >> 3) & 0x03));
+ locp++;
+ *locp = (char)(*locp | ((eval & 0x07) << 5));
+ break;
+ }
+ if((w & 0x0F00) == FU_REGTWO) {
+ if(eval < 0 || eval > 31) {
+ error("register value out of range");
+ break;
+ }
+ locp++;
+ *locp = (char)(*locp | (eval & 0x1F));
+ break;
+ }
+
+ if(!(eattr & DEFINED)) {
+ if(w & FU_PCREL)
+ w = MPCREL | MWORD;
+ else w = MWORD;
+ rmark(sno, loc, 0, w, esym);
+ } else {
+ if(tdb)
+ rmark(sno, loc, tdb, MWORD, NULL);
+ if(w & FU_SEXT) {
+ if(eval + 0x10000 >= 0x20000)
+ goto range;
+ } else
+ if(w & FU_ISBRA) { // Range-check BRA and DBRA
+ if(eval + 0x8000 >= 0x10000)
+ goto range;
+ } else
+ if(eval >= 0x10000)
+ goto range;
+ }
+
+ *locp++ = (char)(eval >> 8);
+ *locp = (char)eval;
+ break;
+ // Fixup LONG forward references;
+ // the long could be unaligned in the section buffer, so be careful (again).
+ case FU_LONG:
+ if((w & 0x0F00) == FU_MOVEI) {
+ address = loc + 4;
+ if(eattr & DEFINED) {
+ for(j = 0; j < fwindex; j++) {
+ if(fwdjump[j] == address) {
+ page_jump = (address & 0xFFFFFF00) - (eval & 0xFFFFFF00);
+ if(page_jump) {
+ if(eval % 4) {
+ err_setup();
+ sprintf(buf, "* \'jump\' at $%08X - destination address not aligned for long page jump, "
+ "insert a \'nop\' before the destination address", address);
+ if(listing > 0) ship_ln(buf);
+ if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
+ else printf("%s\n", buf);
+ }
+ } else {
+ if(!(eval & 0x0000000F) || ((eval - 2) % 4)) {
+ err_setup();
+ sprintf(buf, "* \'jump\' at $%08X - destination address not aligned for short page jump, "
+ "insert a \'nop\' before the destination address", address);
+ if(listing > 0) ship_ln(buf);
+ if(err_flag) write(err_fd, buf, (LONG)strlen(buf));
+ else printf("%s\n", buf);
+ }
+ }
+ // Clear this jump as it has been checked
+ fwdjump[j] = 0;
+ j = fwindex;
+ }
+ }
+ }
+ eval = ((eval >> 16) & 0x0000FFFF) | ((eval << 16) & 0xFFFF0000);
+ flags = (MLONG|MMOVEI);
+ } else flags = MLONG;
+ if(!(eattr & DEFINED)) {
+ rmark(sno, loc, 0, flags, esym);
+ }
+ else if(tdb) {
+ rmark(sno, loc, tdb, flags, NULL);
+ }
+ *locp++ = (char)(eval >> 24);
+ *locp++ = (char)(eval >> 16);
+ *locp++ = (char)(eval >> 8);
+ *locp = (char)eval;
+ break;
+ // Fixup a 3-bit "QUICK" reference in bits 9..1
+ // (range of 1..8) in a word. Really bits 1..3 in a byte.
+ case FU_QUICK:
+ if(!(eattr & DEFINED)) {
+ error("External quick reference");
+ continue;
+ }
+
+ if(eval < 1 || eval > 8)
+ goto range;
+ *locp |= (eval & 7) << 1;
+ break;
+ // Fix up 6502 funny branch
+ case FU_6BRA:
+ eval -= (loc + 1);
+ if(eval + 0x80 >= 0x100)
+ goto range;
+ *locp = (char)eval;
+ break;
+ default:
+ interror(4); // Bad fixup type
+ // NOTREACHED
+ }
+ continue;
+
+ range:
+
+ error("expression out of range");
+ }
+
+ ch = ch->chnext;
+ } while(ch != NULL);
+
+ return(0);
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// SECT.H - Code Generation, Fixups and Section Management
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __SECT_H__
+#define __SECT_H__
+
+#include "rmac.h"
+
+// Macros to deposit code in the current section
+// D_rword deposits a "6502" format (low, high) word (01).
+// D_rlong deposits a MWC "canonical byte order" longword (2301).
+#define D_byte(b) {*chptr++=(char)b; ++sloc; ++ch_size; if(orgactive) ++orgaddr;}
+#define D_word(w) {chcheck(2);*chptr++=(char)(w>>8); *chptr++=(char)w; \
+ sloc+=2; ch_size+=2; if(orgactive) orgaddr += 2;}
+#define D_long(lw) {*chptr++=(char)(lw>>24); *chptr++=(char)(lw>>16);\
+ *chptr++=(char)(lw>>8); *chptr++=(char)lw; \
+ sloc+=4; ch_size += 4; if(orgactive) orgaddr += 4;}
+#define D_rword(w) {*chptr++=(char)w; *chptr++=(char)(w>>8); \
+ sloc+=2; ch_size+=2;if(orgactive) orgaddr += 2;}
+#define D_rlong(lw) {*chptr++=(char)(lw>>16);*chptr++=(char)(lw>>24);\
+ *chptr++=(char)lw;*chptr++=(char)(lw>>8); \
+ sloc+=4; ch_size += 4;if(orgactive) orgaddr += 4;}
+
+#define NSECTS 16 // Max. number of sections
+
+// Tunable (storage) definitions
+#define CH_THRESHOLD 64 // Minimum amount of space in code chunk
+#define CH_CODE_SIZE 2048 // Code chunk normal allocation
+#define CH_FIXUP_SIZE 1024 // Fixup chunk normal allocation
+
+// Section attributes (.scattr)
+#define SUSED 0x8000 // Section is used (really, valid)
+#define SBSS 0x4000 // Section can contain no data
+#define SABS 0x2000 // Section is absolute
+#define SPIC 0x1000 // Section is position-independent code
+
+// Fixup record a WORD of these bits, followed by a loc and then a pointer
+// to a symbol or an ENDEXPR-terminated postfix expression.
+//
+// SYMBOL EXPRESSION
+// ------ ----------
+// ~FU_EXPR FU_EXPR fixup type
+// loc.L loc.L location in section
+// fileno.W fileno.W file number fixup occurred in
+// lineno.W lineno.W line number fixup occurred in
+// symbol.L size.W &symbol / size of expression
+// token.L expression list
+// (etc)
+// ENDEXPR.L (end of expression)
+#define FUMASK 007 // Mask for fixup cases:
+#define FU_QUICK 000 // Fixup 3-bit quick instr field
+#define FU_BYTE 001 // Fixup byte
+#define FU_WORD 002 // Fixup word
+#define FU_WBYTE 003 // Fixup byte (at loc+1)
+#define FU_LONG 004 // Fixup long
+#define FU_BBRA 005 // Fixup byte branch
+#define FU_6BRA 007 // Fixup 6502-format branch offset
+#define FU_SEXT 010 // Ok to sign extend
+#define FU_PCREL 020 // Subtract PC first
+#define FU_EXPR 040 // Expression (not symbol) follows
+
+#define FU_MOVEI 0x0100
+#define FU_JR 0x0200
+#define FU_MJR 0x0300
+#define FU_REGONE 0x0400
+#define FU_NUM15 0x0500
+#define FU_NUM31 0x0600
+#define FU_NUM32 0x0700
+#define FU_REGTWO 0x0800
+#define FU_SUB32 0x1000
+#define FU_ISBRA 0x2000 // Word forward fixup is a BRA or DBRA
+#define FU_LBRA 0x4000 // Long branch, for short branch detect
+#define FU_DONE 0x8000 // Fixup has been done
+
+// Chunks are used to hold generated code and fixup records
+#define CHUNK struct _chunk
+CHUNK {
+ CHUNK *chnext; // Next, previous chunks in section
+ CHUNK *chprev;
+ LONG chloc; // Base addr of this chunk
+ LONG challoc; // #bytes allocated for chunk
+ LONG ch_size; // #bytes chunk actually uses
+ char *chptr; // Data for this chunk
+};
+
+// Section descriptor
+#define SECT struct _sect
+SECT {
+ WORD scattr; // Section attributes
+ LONG sloc; // Current loc-in / size-of section
+ CHUNK *sfcode; // First chunk in section
+ CHUNK *scode; // Last chunk in section
+ CHUNK *sffix; // First fixup chunk
+ CHUNK *sfix; // Last fixup chunk
+};
+
+// A mark is of the form:
+// .W <to+flags> section mark is relative to, and flags in upper byte
+// .L <loc> location of mark in "from" section
+// .W [from] new from section
+// .L [symbol] symbol involved in external reference
+#define MCHUNK struct _mchunk
+MCHUNK {
+ MCHUNK *mcnext; // Next mark chunk
+ PTR mcptr; // Vector of marks
+ LONG mcalloc; // #marks allocted to mark block
+ LONG mcused; // #marks used in block
+};
+
+#define MWORD 0x0000 // Marked word
+#define MLONG 0x0100 // Marked long
+#define MMOVEI 0x0200
+#define MCHFROM 0x8000 // Mark includes change-to-from
+#define MSYMBOL 0x4000 // Mark includes symbol number
+#define MCHEND 0x2000 // Indicates end of mark chunk
+#define MPCREL 0x1000 // Mark is PC-relative
+
+#define MAXFWDJUMPS 1024 // Maximum forward jumps to check
+extern unsigned fwdjump[MAXFWDJUMPS];
+extern unsigned fwindex;
+
+// Globals, external etc
+extern LONG sloc;
+extern WORD scattr;
+extern char *chptr;
+extern LONG ch_size;
+extern int cursect;
+extern SECT sect[];
+extern LONG challoc;
+extern CHUNK *scode;
+
+// Prototypes
+void init_sect(void);
+void switchsect(int);
+void savsect(void);
+int fixtest(int, LONG);
+int chcheck(LONG);
+int fixup(WORD, LONG, TOKEN *);
+int fixups(void);
+int resfix(int);
+
+#endif // __SECT_H__
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// SYMBOL.C - Symbol Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "symbol.h"
+#include "listing.h"
+#include "procln.h"
+#include "error.h"
+
+static SYM *sytab[NBUCKETS]; // User symbol-table header
+int curenv; // Current enviroment number
+SYM *sorder; // * -> Symbols, in order of reference
+SYM *sordtail; // * -> Last symbol in sorder list
+SYM *sdecl; // * -> Symbols, in order of declaration
+SYM *sdecltail; // * -> Last symbol in sdecl list
+
+// Tags for marking symbol spaces
+// a = absolute
+// t = text
+// d = data
+// ! = "impossible!"
+// b = BSS
+static char tdb_text[8] = {
+ 'a', 't', 'd', '!', 'b', SPACE, SPACE, SPACE
+};
+
+//
+// --- Initialize Symbol Table ---------------------------------------------------------------------
+//
+
+void init_sym(void) {
+ int i; // Iterator
+
+ for(i = 0; i < NBUCKETS; ++i) // Initialise symbol hash table
+ sytab[i] = NULL;
+
+ curenv = 1; // Init local symbol enviroment
+ sorder = NULL; // Init symbol-reference list
+ sordtail = NULL;
+ sdecl = NULL; // Init symbol-decl list
+ sdecltail = NULL;
+}
+
+//
+// --- Allocate and Return Pointer to a Copy of a String -------------------------------------------
+//
+
+char *nstring(char *str) {
+ long i;
+ char *s, *d;
+
+ for(i = 0; str[i]; ++i)
+ ;
+ s = d = amem(i + 1);
+ while(*str)
+ *d++ = *str++;
+ *d++ = '\0';
+
+ return(s);
+}
+
+//
+// --- Hash the Print Name and Enviroment Number ---------------------------------------------------
+//
+int syhash(char *name, int envno) {
+ int sum, k; // Hash calculation
+
+ k = 0;
+ for(sum = envno; *name; ++name) {
+ if(k++ == 1)
+ sum += *name << 2;
+ else
+ sum += *name;
+ }
+
+ return(sum & (NBUCKETS - 1));
+}
+
+//
+// --- Make a new symbol of type `type' in enviroment `envno' --------------------------------------
+//
+
+SYM *newsym(char *name, int type, int envno) {
+ int hash; // Symbol hash value
+ SYM *sy; // Pointer to symbol
+
+
+ // Allocate the symbol
+ sy = (SYM *)amem((long)(sizeof(SYM)));
+ if(sy == NULL) {
+ printf("SYMALLOC ERROR (%s)\n", name);
+ return(NULL);
+ }
+
+ sy->sname = nstring(name);
+
+ // Fill-in the symbol
+ sy->stype = (BYTE)type;
+ sy->senv = (WORD)envno;
+ sy->sattr = 0;
+ if(rgpu || rdsp) sy->sattre = RISCSYM;
+ else sy->sattre = 0;
+ sy->svalue = 0;
+
+ // Install symbol in symbol table
+ hash = syhash(name, envno);
+ sy->snext = sytab[hash];
+ sytab[hash] = sy;
+
+ // Append symbol to symbol-order list
+ if(sorder == NULL)
+ sorder = sy; // Add first symbol
+ else
+ sordtail->sorder = sy; // Or append to tail of list
+
+ sy->sorder = NULL;
+ sordtail = sy;
+
+ return(sy); // Return pointer to symbol
+}
+
+//
+// --- Lookup the symbol `name', of the specified type, with the specified enviroment level --------
+//
+
+SYM *lookup(char *name, int type, int envno) {
+ SYM *sy; // Symbol record pointer
+ int k, sum; // Hash bucket calculation
+ char *s; // String pointer
+
+ // Pick a hash-bucket (SAME algorithm as syhash())
+ k = 0;
+ s = name;
+ for(sum = envno; *s;) {
+ if(k++ == 1)
+ sum += *s++ << 2;
+ else sum += *s++;
+ }
+
+ sy = sytab[sum & (NBUCKETS-1)];
+
+ // Do linear-search for symbol in bucket
+ while(sy != NULL) {
+ if(sy->stype == type && // Type, envno and name must match
+ sy->senv == envno &&
+ *name == *sy->sname && // Fast check for first character
+ !strcmp(name, sy->sname))
+ break;
+ else sy = sy->snext;
+ }
+
+ return(sy); // Return NULL or matching symbol
+}
+
+//
+// --- Put symbol on "order-of-declaration" list of symbols ----------------------------------------
+//
+
+void sym_decl(SYM *sym) {
+ if(sym->sattr & SDECLLIST) return; // Already on list
+ sym->sattr |= SDECLLIST; // Mark "already on list"
+
+ if(sdecl == NULL)
+ sdecl = sym; // First on decl-list
+ else
+ sdecltail->sdecl = sym; // Add to end of list
+
+ sym->sdecl = NULL; // Fix up list's tail
+ sdecltail = sym;
+}
+
+//
+// --- Make all referenced, undefined symbols global -----------------------------------------------
+//
+
+int syg_fix(void) {
+ SYM *sy;
+
+ DEBUG printf("~syg_fix()\n");
+
+ // Scan through all symbols;
+ // If a symbol is REFERENCED but not DEFINED, then make it global.
+ for(sy = sorder; sy != NULL; sy = sy->sorder)
+ if(sy->stype == LABEL && sy->senv == 0 &&
+ ((sy->sattr & (REFERENCED|DEFINED)) == REFERENCED))
+ sy->sattr |= GLOBAL;
+
+ return(0);
+}
+
+//
+// --- Convert string to uppercase -----------------------------------------------------------------
+//
+
+int uc_string(char *s) {
+ for(; *s; ++s)
+ if(*s >= 'a' && *s <= 'z')
+ *s -= 32;
+ return(0);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Assign numbers to symbols that are to be exported or imported. The symbol number is put in
+// `.senv'. Return the number of symbols that will be in the symbol table.
+// -------------------------------------------------------------------------------------------------
+//
+
+int sy_assign(char *buf, char *(*constr)()) {
+ SYM *sy;
+ int scount;
+ //int i;
+
+ scount = 0;
+
+ if(buf == NULL)
+ // Append all symbols not appearing on the .sdecl list to the end of the .sdecl list
+ for(sy = sorder; sy != NULL; sy = sy->sorder) {
+
+ // Essentially the same as 'sym_decl()' above:
+ if(sy->sattr & SDECLLIST) continue; // Already on list
+ sy->sattr |= SDECLLIST; // Mark "on the list"
+
+ if(sdecl == NULL) sdecl = sy; // First on decl-list
+ else sdecltail->sdecl = sy; // Add to end of list
+
+ sy->sdecl = NULL; // Fix up list's tail
+ sdecltail = sy;
+ }
+
+ // Run through all symbols (now on the .sdecl list) and assign numbers to them. We also pick
+ // which symbols should be global or not here.
+ for(sy = sdecl; sy != NULL; sy = sy->sdecl) {
+
+ if(sy->sattre & UNDEF_EQUR) continue; // Don't want undefined on our list
+ if(sy->sattre & UNDEF_CC) continue;
+
+ // Export or import external references, and export COMMON blocks.
+ if((sy->stype == LABEL) &&
+ ((sy->sattr & (GLOBAL|DEFINED)) == (GLOBAL|DEFINED) ||
+ (sy->sattr & (GLOBAL|REFERENCED)) == (GLOBAL|REFERENCED)) ||
+ (sy->sattr & COMMON)) {
+ sy->senv = (WORD)scount++;
+ if(buf != NULL) buf = (*constr)(buf, sy, 1);
+ } else
+ // Export vanilla labels (but don't make them global). An exception is made for equates,
+ // which are not exported unless they are referenced.
+ if(sy->stype == LABEL && lsym_flag &&
+ (sy->sattr & (DEFINED|REFERENCED)) != 0 &&
+ (!as68_flag || *sy->sname != 'L') ) {
+ sy->senv = (WORD)scount++;
+ if(buf != NULL) buf = (*constr)(buf, sy, 0);
+ }
+ }
+
+ return(scount);
+}
+
+//
+// --- Generate symbol table for listing file ------------------------------------------------------
+//
+
+int symtable(void) {
+ int i;
+ int j;
+ SYM *q = NULL;
+ SYM *p;
+ SYM *r;
+ SYM *k;
+ SYM **sy;
+ SYM *colptr[4];
+ char ln[150];
+ char ln1[150];
+ char ln2[20];
+ char c, c1;
+ WORD w;
+ int ww;
+ int colhei;
+ extern int pagelen;
+
+ colhei = pagelen - 5;
+
+ // Allocate storage for list headers and partition all labels.
+ // Throw away macros and macro arguments.
+ sy = (SYM **)amem((LONG)(128 * sizeof(LONG)));
+ for(i = 0; i < 128; ++i) sy[i] = NULL;
+
+ for(i = 0; i < NBUCKETS; ++i)
+ for(p = sytab[i]; p != NULL; p = k) {
+ k = p->snext;
+ j = *p->sname;
+ r = NULL;
+ if(p->stype != LABEL) continue; // Ignore non-labels
+ if(p->sattre & UNDEF_EQUR) continue;
+
+ for(q = sy[j]; q != NULL; q = q->snext)
+ if(strcmp(p->sname, q->sname) < 0)
+ break;
+ else r = q;
+
+ if(r == NULL) { // Insert at front of list
+ p->snext = sy[j];
+ sy[j] = p;
+ } else { // Insert in middle or append to list
+ p->snext = r->snext;
+ r->snext = p;
+ }
+ }
+
+ // Link all symbols onto one list again
+ p = NULL;
+ for(i = 0; i < 128; ++i)
+ if((r = sy[i]) != NULL) {
+ if(p == NULL)
+ q = r;
+ else q->snext = r;
+
+ while(q->snext != NULL)
+ q = q->snext;
+
+ if(p == NULL)
+ p = r;
+ }
+
+ eject();
+ strcpy(subttl, "Symbol Table");
+
+ while(p != NULL) {
+ for (i = 0; i < 4; ++i) {
+ colptr[i] = p;
+ for(j = 0; j < colhei; ++j)
+ if(p == NULL)
+ break;
+ else p = p->snext;
+ }
+
+ for(i = 0; i < colhei; ++i) {
+ *ln = EOS;
+ if(colptr[0] == NULL)
+ break;
+
+ for(j = 0; j < 4; ++j) {
+ if((q = colptr[j]) == NULL)
+ break;
+ colptr[j] = q->snext;
+ w = q->sattr;
+ ww = q->sattre;
+ // Pick a tag:
+ // c common
+ // x external reference
+ // g global (export)
+ // space nothing special
+ c1 = SPACE;
+ c = SPACE;
+
+ if(w & COMMON) c = 'c';
+ else if((w & (DEFINED|GLOBAL)) == GLOBAL) c = 'x';
+ else if(w & GLOBAL) c = 'g';
+
+ c1 = tdb_text[w & TDB];
+ if(c == 'x') strcpy(ln2, "external");
+ else {
+ sprintf(ln2, "%08lx", q->svalue);
+ uc_string(ln2);
+ }
+
+ sprintf(ln1, " %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c);
+
+ strcat(ln, ln1);
+ }
+ ship_ln(ln);
+ }
+ eject();
+ }
+
+ return(0);
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// SYMBOL.H - Symbol Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __SYMBOL_H__
+#define __SYMBOL_H__
+
+#include "rmac.h"
+
+// Macros
+#define NBUCKETS 256 // Number of hash buckets (power of 2)
+
+// Globals, externals etc
+extern int curenv;
+extern char subttl[];
+
+// Prototypes
+SYM *lookup(char *, int, int);
+void init_sym(void);
+SYM *newsym(char *, int, int);
+char *nstring(char *);
+void sym_decl(SYM *);
+int syg_fix(void);
+int symtable(void);
+int sy_assign(char *, char *(*)());
+
+#endif // __SYMBOL_H__
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// TOKEN.C - Token Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#include "token.h"
+#include "symbol.h"
+#include "procln.h"
+#include "macro.h"
+#include "error.h"
+
+#define DECL_KW // Declare keyword arrays
+#define DEF_KW // Declare keyword values
+#include "kwtab.h" // Incl generated keyword tables & defs
+
+int lnsave; // 1; strcpy() text of current line
+int curlineno; // Current line number
+int totlines; // Total # of lines
+int mjump_align = 0; // mjump alignment flag
+char lntag; // Line tag
+char *curfname; // Current filename
+char tolowertab[128]; // Uppercase ==> lowercase
+char hextab[128]; // Table of hex values
+char dotxtab[128]; // Table for ".b", ".s", etc.
+char irbuf[LNSIZ]; // Text for .rept block line
+char lnbuf[LNSIZ]; // Text of current line
+WORD filecount; // Unique file number counter
+WORD cfileno; // Current file number
+TOKEN *tok; // Ptr to current token
+TOKEN *etok; // Ptr past last token in tokbuf[]
+TOKEN tokeol[1] = {EOL}; // Bailout end-of-line token
+
+// File record, used to maintain a list of every include file ever visited
+#define FILEREC struct _filerec
+FILEREC {
+ FILEREC *frec_next;
+ char *frec_name;
+};
+
+FILEREC *filerec;
+FILEREC *last_fr;
+
+INOBJ *cur_inobj; // Ptr current input obj (IFILE/IMACRO)
+static INOBJ *f_inobj; // Ptr list of free INOBJs
+static IFILE *f_ifile; // Ptr list of free IFILEs
+static IMACRO *f_imacro; // Ptr list of free IMACROs
+
+static TOKEN tokbuf[TOKBUFSIZE]; // Token buffer (stack-like, all files)
+
+char chrtab[] = {
+ ILLEG, ILLEG, ILLEG, ILLEG, // NUL SOH STX ETX
+ ILLEG, ILLEG, ILLEG, ILLEG, // EOT ENQ ACK BEL
+ ILLEG, WHITE, ILLEG, ILLEG, // BS HT LF VT
+ WHITE, ILLEG, ILLEG, ILLEG, // FF CR SO SI
+
+ ILLEG, ILLEG, ILLEG, ILLEG, // DLE DC1 DC2 DC3
+ ILLEG, ILLEG, ILLEG, ILLEG, // DC4 NAK SYN ETB
+ ILLEG, ILLEG, ILLEG, ILLEG, // CAN EM SUB ESC
+ ILLEG, ILLEG, ILLEG, ILLEG, // FS GS RS US
+
+ WHITE, MULTX, MULTX, SELF, // SP ! " #
+ MULTX+CTSYM, MULTX, SELF, MULTX, // $ % & '
+ SELF, SELF, SELF, SELF, // ( ) * +
+ SELF, SELF, STSYM, SELF, // , - . /
+
+ DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 0 1
+ DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 2 3
+ DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 4 5
+ DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 6 7
+ DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 8 9
+ MULTX, MULTX, // : ;
+ MULTX, MULTX, MULTX, STSYM+CTSYM, // < = > ?
+
+ MULTX, STSYM+CTSYM+HDIGIT, // @ A
+ (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // B C
+ STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // D E
+ STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // F G
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // H I J K
+ (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // L M N O
+
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // P Q R S
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // T U V W
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // X Y Z [
+ SELF, SELF, MULTX, STSYM+CTSYM, // \ ] ^ _
+
+ ILLEG, STSYM+CTSYM+HDIGIT, // ` a
+ (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // b c
+ STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // d e
+ STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // f g
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // h i j k
+ (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // l m n o
+
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // p q r s
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // t u v w
+ STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // x y z {
+ SELF, SELF, SELF, ILLEG // | } ~ DEL
+};
+
+// Names of registers
+static char *regname[] = {
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
+ "pc", "ssp", "usp", "sr", "ccr"
+};
+
+static char *riscregname[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+//
+// --- Make `fnum' the Current `curfname' ----------------------------------------------------------
+//
+
+void setfnum(WORD fnum) {
+ FILEREC *fr;
+
+ for(fr = filerec; fr != NULL && fnum--; fr = fr->frec_next)
+ ;
+
+ if(fr == NULL)
+ curfname = "(*top*)";
+ else
+ curfname = fr->frec_name;
+}
+
+//
+// --- Allocate an IFILE or IMACRO -----------------------------------------------------------------
+//
+
+INOBJ *a_inobj(int typ) {
+ INOBJ *inobj;
+ IFILE *ifile;
+ IMACRO *imacro;
+
+ // Allocate and initialize INOBJ first
+ if(f_inobj == NULL)
+ inobj = (INOBJ *)amem((LONG)sizeof(INOBJ));
+ else {
+ inobj = f_inobj;
+ f_inobj = f_inobj->in_link;
+ }
+
+ switch(typ) {
+ case SRC_IFILE: // Alloc and init an IFILE
+ if(f_ifile == NULL)
+ ifile = (IFILE *)amem((LONG)sizeof(IFILE));
+ else {
+ ifile = f_ifile;
+ f_ifile = f_ifile->if_link;
+ }
+ inobj->inobj.ifile = ifile;
+ break;
+ case SRC_IMACRO: // Alloc and init an IMACRO
+ if(f_imacro == NULL)
+ imacro = (IMACRO *)amem((LONG)sizeof(IMACRO));
+ else {
+ imacro = f_imacro;
+ f_imacro = f_imacro->im_link;
+ }
+ inobj->inobj.imacro = imacro;
+ break;
+ case SRC_IREPT: // Alloc and init an IREPT
+ inobj->inobj.irept = (IREPT *)amem((LONG)sizeof(IREPT));
+ DEBUG printf("alloc IREPT\n");
+ break;
+ }
+
+ // Install INOBJ on top of input stack
+ inobj->in_ifent = ifent; // Record .if context on entry
+ inobj->in_type = (WORD)typ;
+ inobj->in_otok = tok;
+ inobj->in_etok = etok;
+ inobj->in_link = cur_inobj;
+ cur_inobj = inobj;
+
+ return(inobj);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
+// A macro reference is in one of two forms:
+// \name <non-name-character>
+// \{name}
+// A doubled backslash (\\) is compressed to a single backslash (\).
+// Argument definitions have been pre-tokenized, so we have to turn them back into text. This
+// means that numbers, in particular, become hex, regardless of their representation when the macro
+// was invoked. This is a hack.
+// A label may appear at the beginning of the line:
+// :<name><whitespace>
+// (the colon must be in the first column). These labels are stripped before macro expansion takes
+// place.
+// -------------------------------------------------------------------------------------------------
+//
+
+int mexpand(char *src, char *dest, int destsiz) {
+ char *s;
+ char *d = NULL;
+ char *dst; // Next dest slot
+ char *edst; // End+1 of dest buffer
+ int i;
+ int questmark; // \? for testing argument existence
+ TOKEN *tk;
+ char mname[128]; // Assume max size of a formal arg name
+ int macnum;
+ SYM *arg;
+ IMACRO *imacro;
+ char numbuf[20]; // Buffer for text of CONSTs
+
+ imacro = cur_inobj->inobj.imacro;
+ macnum = (int)(imacro->im_macro->sattr);
+
+ --destsiz;
+ dst = dest;
+ edst = dest + destsiz;
+
+ // Check for (and skip over) any "label" on the line
+ s = src;
+ if(*s == ':') {
+ while(*s != EOS && !(chrtab[*s] & WHITE)) ++s;
+ if(*s != EOS) ++s; // Skip first whitespace
+ }
+
+ // Expand the rest of the line
+ while(*s != EOS)
+ if(*s != '\\') { // Copy single character
+ if(dst >= edst)
+ goto overflow;
+ *dst++ = *s++;
+ } else { // Do macro expansion
+ questmark = 0;
+
+ // Do special cases
+ switch(*++s) {
+ case '\\': // \\, \ (collapse to single backslash)
+ if(dst >= edst)
+ goto overflow;
+ *dst++ = *s++;
+ continue;
+ case '?': // \? <macro> set `questmark' flag
+ ++s;
+ questmark = 1;
+ break;
+ case '#': // \#, number of arguments
+ sprintf(numbuf, "%d", (int)imacro->im_nargs);
+ goto copystr;
+ case '!': // \! size suffix supplied on invocation
+ switch((int)imacro->im_siz) {
+ case SIZN: d = ""; break;
+ case SIZB: d = ".b"; break;
+ case SIZW: d = ".w"; break;
+ case SIZL: d = ".l"; break;
+ }
+ goto copy_d;
+ case '~': // ==> unique label string Mnnnn...
+ sprintf(numbuf, "M%ld", curuniq);
+
+ copystr:
+
+ d = numbuf;
+
+ copy_d:
+
+ ++s;
+ while(*d != EOS)
+ if(dst >= edst) goto overflow;
+ else *dst++ = *d++;
+ continue;
+ case EOS:
+ return(error("missing argument name"));
+ }
+
+ // \n ==> argument number 'n', 0..9
+ if(chrtab[*s] & DIGIT) {
+ i = *s++ - '1';
+ if(i < 0)
+ i = 9;
+ goto arg_num;
+ }
+
+ // Get argument name: \name, \{name}
+ d = mname;
+ if(*s != '{') { // \foo
+ do
+ *d++ = *s++;
+ while(chrtab[*s] & CTSYM);
+ } else { // \\{foo}
+ for(++s; *s != EOS && *s != '}';)
+ *d++ = *s++;
+ if(*s != '}') return(error("missing '}'"));
+ else ++s;
+ }
+ *d = EOS;
+
+ // Lookup the argument and copy its (string) value into the destination string
+ DEBUG printf("mname='%s'\n", mname);
+ if((arg = lookup(mname, MACARG, macnum)) == NULL)
+ return(errors("undefined argument: '%s'", mname));
+ else {
+ // Convert a string of tokens (terminated with EOL) back into text. If an argument
+ // is out of range (not specified in the macro invocation) then it is ignored.
+ i = (int)arg->svalue;
+
+ arg_num:
+
+ DEBUG printf("~argnumber=%d\n", i);
+
+ tk = NULL;
+ if(i < imacro->im_nargs)
+ tk = argp[i];
+
+ // \?arg yields:
+ // 0 if the argument is empty or non-existant,
+ // 1 if the argument is not empty
+ if(questmark) {
+ if(tk == NULL || *tk == EOL)
+ questmark = 0;
+ if(dst >= edst)
+ goto overflow;
+ *dst++ = (char)(questmark + '0');
+ continue;
+ }
+
+ if(tk != NULL) // arg# is in range, so expand it
+ while(*tk != EOL) {
+ // Reverse-translation from a token number to a string. This is a hack.
+ // It might be better table-driven.
+ d = NULL;
+ if((*tk >= KW_D0) && !rdsp && !rgpu) {
+ d = regname[(int)*tk++ - KW_D0];
+ goto strcopy;
+ } else if((*tk >= KW_R0) && (*tk <= KW_R31)) {
+ d = riscregname[(int)*tk++ - KW_R0];
+ goto strcopy;
+ } else
+ switch((int)*tk++) {
+ case SYMBOL:
+ d = (char *)*tk++;
+ break;
+ case STRING:
+ d = (char *)*tk++;
+
+ if(dst >= edst)
+ goto overflow;
+ *dst++ = '"';
+
+ while(*d != EOS)
+ if(dst >= edst)
+ goto overflow;
+ else *dst++ = *d++;
+
+ if(dst >= edst)
+ goto overflow;
+ *dst++ = '"';
+ continue;
+ break;
+ case CONST:
+ sprintf(numbuf, "$%lx", (LONG)*tk++);
+ d = numbuf;
+ break;
+ case DEQUALS:
+ d = "==";
+ break;
+ case SET:
+ d = "set";
+ break;
+ case COLON:
+ d = ":";
+ break;
+ case DCOLON:
+ d = "::";
+ break;
+ case GE:
+ d = ">=";
+ break;
+ case LE:
+ d = "<=";
+ break;
+ case NE:
+ d = "<>";
+ break;
+ case SHR:
+ d = ">>";
+ break;
+ case SHL:
+ d = "<<";
+ break;
+ case DOTB:
+ d = ".b";
+ break;
+ case DOTW:
+ d = ".w";
+ break;
+ case DOTL:
+ d = ".l";
+ break;
+ case CR_DATE:
+ d = "^^date";
+ break;
+ case CR_TIME:
+ d = "^^time";
+ break;
+ case CR_DEFINED:
+ d = "^^defined ";
+ break;
+ case CR_REFERENCED:
+ d = "^^referenced ";
+ break;
+ case CR_STREQ:
+ d = "^^streq ";
+ break;
+ case CR_MACDEF:
+ d = "^^macdef ";
+ break;
+ default:
+ if(dst >= edst)
+ goto overflow;
+ *dst++ = (char)*(tk-1);
+ break;
+ }
+
+ // If 'd' != NULL, copy string to destination
+ if(d != NULL) {
+
+ strcopy:
+
+ DEBUG printf("d='%s'\n", d);
+ while(*d != EOS)
+ if(dst >= edst)
+ goto overflow;
+ else *dst++ = *d++;
+ }
+ }
+ }
+ }
+
+
+ *dst = EOS;
+ return(OK);
+
+ overflow:
+
+ *dst = EOS;
+ return(fatal("line too long as a result of macro expansion"));
+}
+
+//
+// --- Get Next Line of Text from a Macro ----------------------------------------------------------
+//
+
+char *getmln(void) {
+ IMACRO *imacro;
+ LONG *strp;
+ unsigned source_addr;
+
+ imacro = cur_inobj->inobj.imacro;
+ strp = imacro->im_nextln;
+
+ if(strp == NULL) // End-of-macro
+ return(NULL);
+
+ imacro->im_nextln = (LONG *)*strp;
+ mexpand((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
+
+ if(!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align) {
+ // if we need to adjust the alignment of the jump source address to meet the rules of
+ // gpu main execution we need to skip the first nop of the macro. This is simpler than
+ // trying to insert nop's mid macro.
+ source_addr = (orgactive) ? orgaddr : sloc;
+ source_addr += 8;
+ if(source_addr % 4) {
+ strp = imacro->im_nextln;
+ if(strp == NULL) return(NULL);
+ imacro->im_nextln = (LONG *)*strp;
+ mexpand((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
+ }
+ mjump_align = 1;
+ }
+
+ return(imacro->im_lnbuf);
+}
+
+//
+// --- Get Next Line of Text from a Repeat Block ---------------------------------------------------
+//
+
+char *getrln(void) {
+ IREPT *irept;
+ LONG *strp;
+
+ irept = cur_inobj->inobj.irept;
+ strp = irept->ir_nextln; // initial null
+
+ // Do repeat at end of .rept block's string list
+ if(strp == NULL) {
+ DEBUG printf("back-to-top-of-repeat-block count=%d\n", irept->ir_count);
+ irept->ir_nextln = irept->ir_firstln; // copy first line
+ if(irept->ir_count-- == 0) {
+ DEBUG printf("end-repeat-block\n");
+ return(NULL);
+ }
+ strp = irept->ir_nextln; //strp
+ }
+
+ strcpy(irbuf, (char*)(irept->ir_nextln + 1));
+
+ DEBUG printf("repeat line='%s'\n", irbuf);
+ irept->ir_nextln = (LONG *)*strp;
+
+ return(irbuf);
+}
+
+//
+// --- Include a Source File used at the Root, and for ".include" Files ----------------------------
+//
+
+int include(int handle, char *fname) {
+ IFILE *ifile;
+ INOBJ *inobj;
+ FILEREC *fr;
+
+ if(verb_flag) printf("[Including: %s]\n", fname); // Verbose mode
+
+ // Alloc and initialize include-descriptors
+ inobj = a_inobj(SRC_IFILE);
+ ifile = inobj->inobj.ifile;
+
+ ifile->ifhandle = handle; // Setup file handle
+ ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
+ ifile->ifoldlineno = curlineno; // Save old line number
+ ifile->ifoldfname = curfname; // Save old filename
+ ifile->ifno = cfileno; // Save old file number
+ cfileno = ++filecount; // Compute new file number
+ curfname = nstring(fname); // Set current filename (alloc storage)
+ curlineno = 0; // Start on line zero
+
+ // Add another file to the file-record
+ fr = (FILEREC *)amem((LONG)sizeof(FILEREC));
+ fr->frec_next = NULL;
+ fr->frec_name = curfname;
+ if(last_fr == NULL)
+ filerec = fr; // Add first filerec
+ else
+ last_fr->frec_next = fr; // Append to list of filerecs
+ last_fr = fr;
+
+ return(OK);
+}
+
+//
+// --- Initialize Tokenizer ------------------------------------------------------------------------
+//
+
+void init_token(void) {
+ int i; // Iterator
+ char *htab = "0123456789abcdefABCDEF"; // Hex character table
+
+ lnsave = 0; // Don't save lines
+ curfname = ""; // No file, empty filename
+ filecount = (WORD)-1;
+ cfileno = (WORD)-1; // cfileno gets bumped to 0
+ curlineno = 0;
+ totlines = 0;
+ etok = tokbuf;
+ f_inobj = NULL;
+ f_ifile = NULL;
+ f_imacro = NULL;
+ cur_inobj = NULL;
+ filerec = NULL;
+ last_fr = NULL;
+ lntag = SPACE;
+
+ // Initialize hex, "dot" and tolower tables
+ for(i = 0; i < 128; ++i) {
+ hextab[i] = -1;
+ dotxtab[i] = 0;
+ tolowertab[i] = (char)i;
+ }
+ for(i = 0; htab[i] != EOS; ++i)
+ hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
+ for(i = 'A'; i <= 'Z'; ++i)
+ tolowertab[i] |= 0x20;
+
+ // These characters are legal immediately after a period
+ dotxtab['b'] = DOTB; // .b .B .s .S
+ dotxtab['B'] = DOTB;
+ dotxtab['s'] = DOTB;
+ dotxtab['S'] = DOTB;
+ dotxtab['w'] = DOTW; // .w .W
+ dotxtab['W'] = DOTW;
+ dotxtab['l'] = DOTL; // .l .L
+ dotxtab['L'] = DOTL;
+ dotxtab['I'] = DOTI; // .l .L
+ dotxtab['I'] = DOTI;
+}
+
+//
+// --- Pop the Current Input Level -----------------------------------------------------------------
+//
+int fpop(void) {
+ INOBJ *inobj;
+ IFILE *ifile;
+ IMACRO *imacro;
+ LONG *p, *p1;
+
+ inobj = cur_inobj;
+ if(inobj != NULL) {
+ // Pop IFENT levels until we reach the conditional assembly context we were at when the
+ // input object was entered.
+ while(ifent != inobj->in_ifent)
+ d_endif();
+
+ tok = inobj->in_otok; // Restore tok and otok
+ etok = inobj->in_etok;
+
+ switch(inobj->in_type) {
+ case SRC_IFILE: // Pop and release an IFILE
+ if(verb_flag)
+ printf("[Leaving: %s]\n", curfname);
+ ifile = inobj->inobj.ifile;
+ ifile->if_link = f_ifile;
+ f_ifile = ifile;
+ close(ifile->ifhandle); // Close source file
+ curfname = ifile->ifoldfname; // Set current filename
+ curlineno = ifile->ifoldlineno; // Set current line#
+ DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
+ cfileno = ifile->ifno; // Restore current file number
+ break;
+ case SRC_IMACRO: // Pop and release an IMACRO
+ imacro = inobj->inobj.imacro;
+ imacro->im_link = f_imacro;
+ f_imacro = imacro;
+ break;
+ case SRC_IREPT: // Pop and release an IREPT
+ DEBUG printf("dealloc IREPT\n");
+ p = inobj->inobj.irept->ir_firstln;
+ while(p != NULL) {
+ p1 = (LONG *)*p;
+ p = p1;
+ }
+ break;
+ }
+
+ cur_inobj = inobj->in_link;
+ inobj->in_link = f_inobj;
+ f_inobj = inobj;
+ }
+
+ return(0);
+}
+
+//
+// --- Get line from file into buf, return NULL on EOF or ptr to the start of a null-term line -----
+//
+
+char *getln(void) {
+ IFILE *fl;
+ int i, j;
+ char *p, *d;
+ int readamt;
+
+ readamt = -1; // 0 if last read() yeilded 0 bytes
+ fl = cur_inobj->inobj.ifile;
+
+ for(;;) {
+ // Scan for next end-of-line; handle stupid text formats by treating \r\n the same as \n.
+ // (lone '\r' at end of buffer means we have to check for '\n').
+ i = 0;
+ j = fl->ifcnt;
+ d = &fl->ifbuf[fl->ifind];
+
+ for(p = d; i < j; ++i, ++p) {
+ if(*p == '\r' || *p == '\n') {
+ ++i;
+ if(*p == '\r') {
+ if(i >= j) {
+ break; // Look for '\n' to eat
+ } else if(p[1] == '\n') {
+ ++i;
+ }
+ }
+
+ *p = '\0';
+
+ fl->ifind += i;
+ fl->ifcnt -= i;
+ return(d);
+ }
+ }
+
+ // Handle hanging lines by ignoring them (Input file is exhausted, no \r or \n on last line)
+ if(!readamt && fl->ifcnt) {
+ fl->ifcnt = 0;
+ *p = '\0';
+ return(NULL);
+ }
+
+ // Truncate and return absurdly long lines.
+ if(fl->ifcnt >= QUANTUM) {
+ fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
+ fl->ifcnt = 0;
+ return(&fl->ifbuf[fl->ifind]);
+ }
+
+ // Relocate what's left of a line to the beginning of the buffer, and read some more of the
+ // file in; return NULL if the buffer's empty and on EOF.
+ if(fl->ifind != 0) {
+ p = &fl->ifbuf[fl->ifind];
+ d = &fl->ifbuf[fl->ifcnt & 1];
+ for(i = 0; i < fl->ifcnt; ++i)
+ *d++ = *p++;
+ fl->ifind = fl->ifcnt & 1;
+ }
+
+ if((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
+ return(NULL);
+
+ if((fl->ifcnt += readamt) == 0)
+ return(NULL);
+ }
+}
+
+//
+// --- Tokenize a Line -----------------------------------------------------------------------------
+//
+
+int tokln(void) {
+ char *ln = NULL; // Ptr to current position in line
+ char *p; // Random character ptr
+ TOKEN *tk; // Token-deposit ptr
+ int state = 0; // State for keyword detector
+ int j = 0; // Var for keyword detector
+ char c; // Random char
+ VALUE v; // Random value
+ char *nullspot = NULL; // Spot to clobber for SYMBOL terminatn
+ int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
+ char c1;
+
+ retry:
+
+ if(cur_inobj == NULL) // Return EOF if input stack is empty
+ return(TKEOF);
+
+ // Get another line of input from the current input source: a file, a macro, or a repeat-block
+ switch(cur_inobj->in_type) {
+ // Include-file:
+ // o handle EOF;
+ // o bump source line number;
+ // o tag the listing-line with a space;
+ // o kludge lines generated by Alcyon C.
+ case SRC_IFILE:
+ if((ln = getln()) == NULL) {
+ fpop(); // Pop input level
+ goto retry; // Try for more lines
+ }
+ ++curlineno; // Bump line number
+ lntag = SPACE;
+ if(as68_flag) {
+ // AS68 compatibility, throw away all lines starting with back-quotes, tildes, or '*'
+ // On other lines, turn the first '*' into a semi-colon.
+ if(*ln == '`' || *ln == '~' || *ln == '*') *ln = ';';
+ else for(p = ln; *p != EOS; ++p) {
+ if(*p == '*') {
+ *p = ';';
+ break;
+ }
+ }
+ }
+ break;
+
+ // Macro-block:
+ // o Handle end-of-macro;
+ // o tag the listing-line with an at (@) sign.
+ case SRC_IMACRO:
+ if((ln = getmln()) == NULL) {
+ exitmac(); // Exit macro (pop args, do fpop(), etc)
+ goto retry; // Try for more lines...
+ }
+ lntag = '@';
+ break;
+
+ // Repeat-block:
+ // o Handle end-of-repeat-block;
+ // o tag the listing-line with a pound (#) sign.
+ case SRC_IREPT:
+ if((ln = getrln()) == NULL) {
+ fpop();
+ goto retry;
+ }
+ lntag = '#';
+ break;
+ }
+
+ // Save text of the line. We only do this during listings and within macro-type blocks,
+ // since it is expensive to unconditionally copy every line.
+ if(lnsave) strcpy(lnbuf, ln);
+
+ // General house-keeping
+ tok = tokeol; // Set "tok" to EOL in case of error
+ tk = etok; // Reset token ptr
+ stuffnull = 0; // Don't stuff nulls
+ ++totlines; // Bump total #lines assembled
+
+ // See if the entire line is a comment. This is a win if the programmer puts in lots of comments
+ if(*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln+1) == '/'))) goto goteol;
+
+ // Main tokenization loop;
+ // o skip whitespace;
+ // o handle end-of-line;
+ // o handle symbols;
+ // o handle single-character tokens (operators, etc.);
+ // o handle multiple-character tokens (constants, strings, etc.).
+ for(; *ln != EOS;) {
+ // Skip whitespace, handle EOL
+ while((int)chrtab[*ln] & WHITE)
+ ++ln;
+
+ // Handle EOL, comment with ';'
+ if(*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln+1) == '/')))
+ break;
+
+ // Handle start of symbol. Symbols are null-terminated in place. The termination is
+ // always one symbol behind, since there may be no place for a null in the case that
+ // an operator immediately follows the name.
+ c = chrtab[*ln];
+ if(c & STSYM) {
+ if(stuffnull) // Terminate old symbol
+ *nullspot = EOS;
+ v = 0; // Assume no DOT attrib follows symbol
+ stuffnull = 1;
+ p = nullspot = ln++; // Nullspot -> start of this symbol
+
+ // Find end of symbol (and compute its length)
+ for(j = 1; (int)chrtab[*ln] & CTSYM; ++j)
+ ++ln;
+
+ // Handle "DOT" special forms (like ".b") that follow a normal symbol or keyword:
+ if(*ln == '.') {
+ *ln++ = EOS; // Terminate symbol
+ stuffnull = 0; // And never try it again
+
+ // Character following the `.' must have a DOT attribute, and the chararacter after
+ // THAT one must not have a start-symbol attribute (to prevent symbols that look
+ // like, for example, "zingo.barf", which might be a good idea anyway....)
+ if((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
+ return(error("[bwsl] must follow `.' in symbol"));
+ v = (VALUE)dotxtab[*ln++];
+ if((int)chrtab[*ln] & CTSYM)
+ return(error("misuse of `.', not allowed in symbols"));
+ }
+
+ // If the symbol is small, check to see if it's really the name of a register.
+ if(j <= KWSIZE) {
+ for(state = 0; state >= 0;) {
+ j = (int)tolowertab[*p++];
+ j += kwbase[state];
+ if(kwcheck[j] != state) {
+ j = -1;
+ break;
+ }
+
+ if(*p == EOS || p == ln) {
+ j = kwaccept[j];
+ break;
+ }
+
+ state = kwtab[j];
+ }
+ } else {
+ j = -1;
+ }
+
+ //make j = -1 if time, date etc with no preceeding ^^
+ //defined, referenced, streq, macdef, date and time
+ switch((TOKEN)j) {
+ case 112: // defined
+ case 113: // referenced
+ case 118: // streq
+ case 119: // macdef
+ case 120: // time
+ case 121: // date
+ j = -1;
+ break;
+ }
+
+ if(j < 0 || state < 0) {
+ *tk++ = SYMBOL;
+ *tk++ = (TOKEN)nullspot;
+ } else {
+ *tk++ = (TOKEN)j;
+ stuffnull = 0;
+ }
+
+ if(v) // Record attribute token (if any)
+ *tk++ = (TOKEN)v;
+
+ if(stuffnull) // Arrange for string termination
+ nullspot = ln;
+ continue;
+ }
+
+ // Handle identity tokens
+ if(c & SELF) {
+ *tk++ = *ln++;
+ continue;
+ }
+
+ // Handle multiple-character tokens
+ if(c & MULTX) {
+ switch(*ln++) {
+ case '!': // ! or !=
+ if(*ln == '=') {
+ *tk++ = NE;
+ ++ln;
+ } else *tk++ = '!';
+ continue;
+ case '\'': // 'string'
+ case '\"': // "string"
+ c1 = ln[-1];
+ *tk++ = STRING;
+ *tk++ = (TOKEN)ln;
+
+ for(p = ln; *ln != EOS && *ln != c1;) {
+ c = *ln++;
+ if(c == '\\')
+ switch(*ln++) {
+ case EOS:
+ return(error("unterminated string"));
+ case 'e':
+ c = '\033';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case '\"':
+ c = '\"';
+ break;
+ case '\'':
+ c = '\'';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ default:
+ warn("bad backslash code in string");
+ --ln;
+ break;
+ }
+ *p++ = c;
+ }
+
+ if(*ln++ != c1)
+ return(error("unterminated string"));
+ *p++ = EOS;
+ continue;
+ case '$': // $, hex constant
+ if((int)chrtab[*ln] & HDIGIT) {
+ v = 0;
+ while((int)hextab[*ln] >= 0)
+ v = (v << 4) + (int)hextab[*ln++];
+ if(*ln == '.') {
+ if((*(ln+1) == 'b') || (*(ln+1) == 'B')) { v &= 0x000000FF; ln += 2; }
+ if((*(ln+1) == 'w') || (*(ln+1) == 'W')) { v &= 0x0000FFFF; ln += 2; }
+ if((*(ln+1) == 'l') || (*(ln+1) == 'L')) { ln += 2; }
+ }
+ *tk++ = CONST;
+ *tk++ = v;
+ } else *tk++ = '$';
+ continue;
+ case '<': // < or << or <> or <=
+ switch(*ln) {
+ case '<':
+ *tk++ = SHL;
+ ++ln;
+ continue;
+ case '>':
+ *tk++ = NE;
+ ++ln;
+ continue;
+ case '=':
+ *tk++ = LE;
+ ++ln;
+ continue;
+ default:
+ *tk++ = '<';
+ continue;
+ }
+ case ':': // : or ::
+ if(*ln == ':') {
+ *tk++ = DCOLON;
+ ++ln;
+ } else *tk++ = ':';
+ continue;
+ case '=': // = or ==
+ if(*ln == '=') {
+ *tk++ = DEQUALS;
+ ++ln;
+ } else *tk++ = '=';
+ continue;
+ case '>': // > or >> or >=
+ switch(*ln) {
+ case '>':
+ *tk++ = SHR;
+ ++ln;
+ continue;
+ case '=':
+ *tk++ = GE;
+ ++ln;
+ continue;
+ default:
+ *tk++ = '>';
+ continue;
+ }
+ case '%': // % or binary constant
+ if(*ln < '0' || *ln > '1') {
+ *tk++ = '%';
+ continue;
+ }
+ v = 0;
+ while(*ln >= '0' && *ln <= '1')
+ v = (v << 1) + *ln++ - '0';
+ if(*ln == '.') {
+ if((*(ln+1) == 'b') || (*(ln+1) == 'B')) { v &= 0x000000FF; ln += 2; }
+ if((*(ln+1) == 'w') || (*(ln+1) == 'W')) { v &= 0x0000FFFF; ln += 2; }
+ if((*(ln+1) == 'l') || (*(ln+1) == 'L')) { ln += 2; }
+ }
+ *tk++ = CONST;
+ *tk++ = v;
+ continue;
+ case '@': // @ or octal constant
+ if(*ln < '0' || *ln > '7') {
+ *tk++ = '@';
+ continue;
+ }
+ v = 0;
+ while(*ln >= '0' && *ln <= '7')
+ v = (v << 3) + *ln++ - '0';
+ if(*ln == '.') {
+ if((*(ln+1) == 'b') || (*(ln+1) == 'B')) { v &= 0x000000FF; ln += 2; }
+ if((*(ln+1) == 'w') || (*(ln+1) == 'W')) { v &= 0x0000FFFF; ln += 2; }
+ if((*(ln+1) == 'l') || (*(ln+1) == 'L')) { ln += 2; }
+ }
+ *tk++ = CONST;
+ *tk++ = v;
+ continue;
+ case '^': // ^ or ^^ <operator-name>
+ if(*ln != '^') {
+ *tk++ = '^';
+ continue;
+ }
+
+ if(((int)chrtab[*++ln] & STSYM) == 0) {
+ error("invalid symbol following ^^");
+ continue;
+ }
+
+ p = ln++;
+ while((int)chrtab[*ln] & CTSYM)
+ ++ln;
+
+ for(state = 0; state >= 0;) {
+ // Get char, convert to lowercase
+ j = *p++;
+ if(j >= 'A' && j <= 'Z')
+ j += 0x20;
+
+ j += kwbase[state];
+ if(kwcheck[j] != state) {
+ j = -1;
+ break;
+ }
+
+ if(*p == EOS || p == ln) {
+ j = kwaccept[j];
+ break;
+ }
+ state = kwtab[j];
+ }
+
+ if(j < 0 || state < 0) {
+ error("unknown symbol following ^^");
+ continue;
+ }
+
+ *tk++ = (TOKEN)j;
+ continue;
+ default:
+ interror(2); // Bad MULTX entry in chrtab
+ continue;
+ }
+ }
+
+
+ // Handle decimal constant
+ if(c & DIGIT) {
+ v = 0;
+ while((int)chrtab[*ln] & DIGIT)
+ v = (v * 10) + *ln++ - '0';
+ if(*ln == '.') {
+ if((*(ln+1) == 'b') || (*(ln+1) == 'B')) { v &= 0x000000FF; ln += 2; }
+ if((*(ln+1) == 'w') || (*(ln+1) == 'W')) { v &= 0x0000FFFF; ln += 2; }
+ if((*(ln+1) == 'l') || (*(ln+1) == 'L')) { ln += 2; }
+ }
+ *tk++ = CONST;
+ *tk++ = v;
+ continue;
+ }
+
+ // Handle illegal character
+ return(error("illegal character"));
+ }
+
+ // Terminate line of tokens and return "success."
+
+ goteol:
+
+ tok = etok; // Set tok to beginning of line
+ if(stuffnull) // Terminate last SYMBOL
+ *nullspot = EOS;
+ *tk++ = EOL;
+
+ return(OK);
+}
+
+//
+// -------------------------------------------------------------------------------------------------
+// .GOTO <label> goto directive
+//
+// The label is searched for starting from the first line of the current, enclosing macro
+// definition. If no enclosing macro exists, an error is generated.
+//
+// A label is of the form:
+//
+// :<name><whitespace>
+//
+// The colon must appear in column 1. The label is stripped prior to macro expansion, and is NOT
+// subject to macro expansion. The whitespace may also be EOL.
+// -------------------------------------------------------------------------------------------------
+//
+
+//int d_goto(WORD siz) {
+int d_goto(void) {
+ char *sym; // Label to search for
+ LONG *defln; // Macro definition strings
+ char *s1; // Temps for string comparison
+ char *s2;
+ IMACRO *imacro; // Macro invocation block
+
+ // Setup for the search
+ if(*tok != SYMBOL) return(error("missing label"));
+ sym = (char *)tok[1];
+ tok += 2;
+
+ if(cur_inobj->in_type != SRC_IMACRO) return(error("goto not in macro"));
+ imacro = cur_inobj->inobj.imacro;
+ defln = (LONG *)imacro->im_macro->svalue;
+
+ // Find the label, starting with the first line.
+ for(; defln != NULL; defln = (LONG *)*defln)
+ if(*(char *)(defln + 1) == ':') {
+ // Compare names (sleazo string compare)
+ s1 = sym;
+ s2 = (char *)(defln + 1) + 1;
+ while(*s1 == *s2)
+ if(*s1 == EOS) break;
+ else {
+ ++s1;
+ ++s2;
+ }
+
+ // Found the label, set new macro next-line and return.
+ if((*s2 == EOS) || ((int)chrtab[*s2] & WHITE)) {
+ imacro->im_nextln = defln;
+ return(0);
+ }
+ }
+
+ return(error("goto label not found"));
+}
--- /dev/null
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// TOKEN.H - Token Handling
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+
+#ifndef __TOKEN_H__
+#define __TOKEN_H__
+
+#include "rmac.h"
+//#include "risca.h"
+
+// Include Files and Macros
+#define SRC_IFILE 0 // Input source is IFILE
+#define SRC_IMACRO 1 // Input source is IMACRO
+#define SRC_IREPT 2 // Input source is IREPT
+
+// Macros
+#define INOBJ struct _inobj
+#define IUNION union _iunion
+#define IFILE struct _incldfile
+#define IMACRO struct _imacro
+#define IREPT struct _irept
+#define IFENT struct _ifent
+
+// Tunable definitions
+#define LNSIZ 256 // Maximum size of a line of text
+#define TOKBUFSIZE 400 // Size of token-line buffer
+#define QUANTUM 4096L // #bytes to eat at a time from a file
+#define LNBUFSIZ (QUANTUM*2) // Size of file's buffer
+#define KWSIZE 7 // Maximum size of keyword in kwtab.h
+
+// (Normally) non-printable tokens
+#define COLON ':' // : (grumble: GNUmacs hates ':')
+#define CONST 'a' // CONST <value>
+#define ACONST 'A' // ACONST <value> <attrib>
+#define STRING 'b' // STRING <address>
+#define SYMBOL 'c' // SYMBOL <address>
+#define EOL 'e' // End of line
+#define TKEOF 'f' // End of file (or macro)
+#define DEQUALS 'g' // ==
+#define SET 149 // Set
+#define REG 'R' // Reg
+#define DCOLON 'h' // ::
+#define GE 'i' // >=
+#define LE 'j' // <=
+#define NE 'k' // <> or !=
+#define SHR 'l' // >>
+#define SHL 'm' // <<
+#define UNMINUS 'n' // Unary '-'
+#define DOTB 'B' // .b or .B or .s or .S
+#define DOTW 'W' // .w or .W
+#define DOTL 'L' // .l or .L
+#define DOTI 'I' // .l or .L
+#define ENDEXPR 'E' // End of expression
+
+// ^^ operators
+#define CR_DEFINED 'p' // ^^defined - is symbol defined?
+#define CR_REFERENCED 'q' // ^^referenced - was symbol referenced?
+#define CR_STREQ 'v' // ^^streq - compare two strings
+#define CR_MACDEF 'w' // ^^macdef - is macro defined?
+#define CR_TIME 'x' // ^^time - DOS format time
+#define CR_DATE 'y' // ^^date - DOS format date
+
+// Character Attributes
+#define ILLEG 0 // Illegal character (unused)
+#define DIGIT 1 // 0-9
+#define HDIGIT 2 // A-F, a-f
+#define STSYM 4 // A-Z, a-z, _~.
+#define CTSYM 8 // A-Z, a-z, 0-9, _~$?
+#define SELF 16 // Single-character tokens: ( ) [ ] etc
+#define WHITE 32 // Whitespace (space, tab, etc.)
+#define MULTX 64 // Multiple-character tokens
+#define DOT 128 // [bwlsBWSL] for what follows a `.'
+
+// Conditional assembly structures
+IFENT {
+ IFENT *if_prev; // Ptr prev .if state block (or NULL)
+ WORD if_state; // 0:enabled, 1:disabled
+};
+
+// Pointer to IFILE or IMACRO
+IUNION {
+ IFILE *ifile;
+ IMACRO *imacro;
+ IREPT *irept;
+};
+
+// Ptr to IFILEs, IMACROs, and so on; back-ptr to previous input objects
+INOBJ {
+ WORD in_type; // 0=IFILE, 1=IMACRO ...
+ IFENT *in_ifent; // Pointer to .if context on entry
+ INOBJ *in_link; // Pointer to previous INOBJ
+ TOKEN *in_otok; // Old `tok' value
+ TOKEN *in_etok; // Old `etok' value
+ IUNION inobj; // IFILE or IMACRO ...
+};
+
+// Information about a file
+IFILE {
+ IFILE *if_link; // Pointer to ancient IFILEs
+ char *ifoldfname; // Old file's name
+ int ifoldlineno; // Old line number
+ int ifind; // Position in file buffer
+ int ifcnt; // #chars left in file buffer
+ int ifhandle; // File's descriptor
+ WORD ifno; // File number
+ char ifbuf[LNBUFSIZ]; // Line buffer
+};
+
+// Information about a macro invocation
+IMACRO {
+ IMACRO *im_link; // Pointer to ancient IMACROs
+ LONG *im_nextln; // Next line to include
+ WORD im_nargs; // # of arguments supplied on invocation
+ WORD im_siz; // Size suffix supplied on invocation
+ LONG im_olduniq; // Old value of 'macuniq'
+ SYM *im_macro; // Pointer to macro we're in
+ char im_lnbuf[LNSIZ]; // Line buffer
+};
+
+// Information about a .rept invocation
+IREPT {
+ LONG *ir_firstln; // Pointer to first line
+ LONG *ir_nextln; // Pointer to next line
+ VALUE ir_count; // Repeat count (decrements)
+};
+
+// Globals, externals etc
+extern int lnsave;
+extern int curlineno;
+extern char *curfname;
+extern WORD cfileno;
+extern TOKEN *tok;
+extern char lnbuf[];
+extern char lntag;
+extern char tolowertab[];
+extern INOBJ *cur_inobj;
+extern unsigned orgactive;
+extern unsigned orgaddr;
+extern LONG sloc;
+extern int mjump_align;
+
+// Prototypes
+int include(int, char *);
+void init_token(void);
+void setfnum(WORD);
+int tokln(void);
+int fpop(void);
+//int d_goto(WORD);
+int d_goto(void);
+INOBJ *a_inobj(int);
+
+#endif // __TOKEN_H__
\ No newline at end of file
--- /dev/null
+//
+// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// VERSION.H - Version Information
+// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
+// Source Utilised with the Kind Permission of Landon Dyer
+//
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+// Release Information
+
+#define MAJOR 1 // Major version number
+#define MINOR 1 // Minor version number
+#define PATCH 0 // Patch release number
+
+#endif // __VERSION_H__