68kgen.o
68ktab.h
68kmn
+6502kw.h
+opkw.h
*.o
*~
kwtab.h
int d_prgflags(void);
int d_opt(void);
int d_dsp(void);
+int d_objproc(void);
void SetLargestAlignment(int);
// Directive handler table
d_68882, // 63 .68882
d_56001, // 64 .56001
d_nofpu, // 65 nofpu
- d_opt, // 58 .opt
+ d_opt, // 66 .opt
+ d_objproc, // 67 .objproc
};
{
uint64_t address;
- if (!rgpu && !rdsp && !m6502)
- return error(".org permitted only in gpu/dsp and 6502 sections");
+ if (!rgpu && !rdsp && !robjproc && !m6502)
+ return error(".org permitted only in GPU/DSP/OP and 6502 sections");
if (abs_expr(&address) == ERROR)
{
return ERROR;
}
- if (rgpu | rdsp)
+ if (rgpu | rdsp | robjproc)
{
orgaddr = address;
orgactive = 1;
uint16_t tdb = eattr & TDB;
uint16_t defined = eattr & DEFINED;
- if ((challoc - ch_size) < 4)
- chcheck(4);
-
switch (siz)
{
case SIZB:
D_long(eval);
}
+
break;
case SIZQ:
// 64-bit size
// Shamus: We only handle DC.Q type stuff, will have to add fixups
// and stuff later (maybe... might not be needed...)
- D_quad(eval);
+ // DEFINITELY NEED FIXUPS HERE!
+ if (!defined)
+ {
+ AddFixup(FU_QUAD, sloc, exprbuf);
+ D_quad(0LL);
+ }
+ else
+ {
+ D_quad(eval);
+ }
+
break;
case SIZS:
// 32-bit float size
}
else
{
- if (tdb)
- MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
+//Would this *ever* happen?
+// if (tdb)
+// MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
PTR ptr;
ptr.u64 = &eval;
}
else
{
- if (tdb)
- MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
+//Would this *ever* happen?
+// if (tdb)
+// MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
PTR ptr;
ptr.u64 = &eval;
}
else
{
- if (tdb)
- MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
+//Would this *ever* happen?
+// if (tdb)
+// MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
PTR ptr;
ptr.u64 = &eval;
//
int d_68000(void)
{
- rgpu = rdsp = 0;
+ rgpu = rdsp = robjproc = 0;
// Switching from gpu/dsp sections should reset any ORG'd Address
orgactive = 0;
orgwarning = 0;
rgpu = 1; // Set GPU assembly
rdsp = 0; // Unset DSP assembly
+ robjproc = 0; // Unset OP assembly
regbank = BANK_N; // Set no default register bank
return 0;
}
rdsp = 1; // Set DSP assembly
rgpu = 0; // Unset GPU assembly
+ robjproc = 0; // Unset OP assembly
regbank = BANK_N; // Set no default register bank
return 0;
}
}
+//
+// Define start of OP object list (allows the use of ORG)
+//
+int d_objproc(void)
+{
+ if ((cursect != TEXT) && (cursect != DATA))
+ {
+ error(".objproc 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 (!robjproc)
+ {
+ orgactive = 0;
+ orgwarning = 0;
+ }
+
+ robjproc = 1; // Set OP assembly
+ rgpu = 0; // Unset GPU assembly
+ rdsp = 0; // Unset DSP assembly
+ return OK;
+}
+
+
//
// Undefine a macro - .undefmac macname [, macname...]
//
--- /dev/null
+A Few Notes on the New Object Processor Assembler
+-------------------------------------------------
+
+Q: What is it?
+
+A: An assembler to generate object lists for the Atari Jaguar's Object
+ processor.
+
+
+Q: Why is it here?
+
+A: To really utilize the OP properly, it needs an assembler. Otherwise, what
+ happens is you end up writing an assembler in your code to assemble the OP
+ list, and that's a real drag--something that *should* be handled by a proper
+ assembler.
+
+
+Q: How do I use it?
+
+A: The OP assembler works similarly to the RISC assembler; to enter the OP
+ assembler, you put the .objproc directive in your code (N.B.: like the RISC
+ assembler, it only works in a TEXT or DATA section). From there, you build
+ the OP list how you want it and go from there. A few caveats: you will want
+ to put a .org directive at the top of your list, and labels that you want to
+ be able to address in 68xxx code (for moving from a data section to an
+ address where it will be executed by the OP, for example) should be created
+ in .68xxx mode.
+
+
+Q: What are the opcodes?
+
+A: They are bitmap, scbitmap, gpuobj, branch, stop, nop, and jump. nop and jump
+ are psuedo-ops, they are there as a convenience to the coder.
+
+
+Q: What are the proper forms for these opcodes?
+
+A: They are as follows:
+
+ bitmap <data addr>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>, <bpp>,
+ <pallete idx>, <flags>, <firstpix>, <pitch>
+ scbitmap <data addr>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>,
+ <xscale>, <yscale>, <remainder>, <bpp>, <pallete idx>,
+ <flags>, <firstpix>, <pitch>
+ gpuobj <line #>, <userdata> (bits 14-63 of this object)
+ branch VC <condition (<, =, >)> <line #>, <link addr>
+ branch OPFLAG, <link addr>
+ branch SECHALF, <link addr>
+ stop
+ nop
+ jump <link addr>
+
+ Note that the <flags> field in bitmap and scbitmap objects consist of the
+ following: REFLECT, RMW, TRANS, RELEASE. They can be in any order (and
+ should be separated by whitespace *only*), and you can only put a maximum of
+ four of them in. Further note that with bitmap and scbitmap objects, all the
+ parameters after <data addr> are optional--if they are omitted, they will
+ use defaults (mostly 0, but 1 is the default for pitch). Also, in the
+ scbitmap object, the <xscale>, <yscale>, and <remainder> fields can be
+ floating point constants/expressions. <data addr> can refer to any address
+ defined (even external!) and the linker (rln v1.6.0 or greater) will
+ properly fix up the address.
+
+
+Q: What do they do?
+
+A: Pretty much what you expect. It's beyond the scope of this little note to
+ explain the Jaguar's Object Processor and how it operates, so you'll have to
+ seek explanations for how they work elsewhere.
+
+
+Q: Why do I want to put a .org directive at the top of my list?
+
+A: You want to put a .org directive at the top of your list because otherwise
+ the assembler will not know where in memory the object list is supposed
+ go--then when you move it to its destination, the object link addresses will
+ all be wrong and it won't work.
+
+
+Q: Why would I copy my object list to another memory location?
+
+A: Simple: because the OP destroys the list as it uses it to render the screen.
+ If you don't keep a fresh copy stashed away somewhere to refresh it before
+ the next frame is rendered, what you see on the screen will not be what you
+ expect, as the OP has scribbled all over it!
+
+
+Q: Does the assembler do anything behind my back?
+
+A: Yes, it will emit NOPs to ensure that bitmaps and scbitmaps are on proper
+ memory boundaries, and fixup link addresses as necessary. This is needed
+ because of a quirk in how the OP works (it ORs constants on the address
+ lines to get the phrases it needs and if they are not zeroes, it will fail
+ in bizarre ways).
+
+
+Q: Why can't I define the link addresses for all the objects?
+
+A: You really, *really* don't want to do this. Trust me on this one.
+
+
+Q: How about an example of an object list?
+
+A: Here you go:
+
+ objList = $10000
+ bRam = $20000
+;
+ .68000
+objects: ; This is the label you will use to address this in 68K code
+ .objproc ; Engage the OP assembler
+ .org objList ; Tell the OP assembler where the list will execute
+;
+ branch VC < 69, .stahp ; Branch to the STOP object if VC < 69
+ branch VC > 241, .stahp ; Branch to the STOP object if VC > 241
+ bitmap bRAM, 22, 70, 24, 24, 22, 4
+ bitmap bRAM, 20+96+96, 70, 24, 24, 22, 4, 0, REFLECT
+ scbitmap tms, 20, 70, 1, 1, 8, 3.0, 3.0, 2.9999, 0, 0, TRANS
+ scbitmap tmsShadow, 23, 73, 1, 1, 8, 3.0, 3.0, 2.9999, 0, 3, TRANS
+ bitmap sbRelBM, 30, 108, 3, 3, 8, 0, 1, TRANS
+ bitmap txt1BM, 46, 132, 3, 3, 8, 0, 2, TRANS
+ bitmap txt2BM, 46, 148, 3, 3, 8, 0, 2, TRANS
+ bitmap txt3BM, 22, 164, 3, 3, 8, 0, 2, TRANS
+ jump .haha
+.stahp:
+ stop
+.haha:
+ jump .stahp
+
// 68881/68882/68040 only
if (w)
{
- if (tdb)
- MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
+//Would a floating point value *ever* need to be fixed up as if it were an address? :-P
+// if (tdb)
+// MarkRelocatable(cursect, sloc, tdb, MSINGLE, NULL);
// The value passed back from expr() is an internal C double;
// so we have to access it as such then convert it to an
// 68881/68882/68040 only
if (w)
{
- if (tdb)
- MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
+//Would a floating point value *ever* need to be fixed up as if it were an address? :-P
+// if (tdb)
+// MarkRelocatable(cursect, sloc, tdb, MDOUBLE, NULL);
PTR p;
p.u64 = &aNexval;
// 68881/68882/68040 only
if (w)
{
- if (tdb)
- MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
+//Would a floating point value *ever* need to be fixed up as if it were an address? :-P
+// if (tdb)
+// MarkRelocatable(cursect, sloc, tdb, MEXTEND, NULL);
PTR p;
p.u64 = &aNexval;
#include "fltpoint.h"
#include <float.h>
#include <math.h>
+#include <stdio.h>
//
// Check for IEEE-754 conformance (C99 compilers should be OK here)
out[11] = intMant & 0xFF;
}
+
+//
+// Convert a host native floating point number to a fixed point number.
+//
+uint64_t DoubleToFixedPoint(double d, int intBits, int fracBits)
+{
+ uint8_t signBit = (signbit(d) ? 1 : 0);
+
+ // Ensure what we're working on is positive...
+ if (d < 0)
+ d *= -1;
+
+ double scaleFactor = (double)(1 << fracBits);
+ uint64_t result = (uint64_t)(d * scaleFactor);
+
+ // Invert the result, if necessary
+ if (signBit == 1)
+ result = (result = 0xFFFFFFFFFFFFFFFFLL) + 1;
+
+ return result;
+}
+
//
-// Cross-platform floating point handling
+// Cross-platform floating point handling (fixed point handling too!)
//
// by James Hammons
// (C) 2018 Underground Software
//
+#ifndef __FLTPOINT_H__
+#define __FLTPOINT_H__
+
#include <stdint.h>
uint32_t FloatToIEEE754(float f);
uint64_t DoubleToIEEE754(double d);
void DoubleToExtended(double d, uint8_t out[]);
+uint64_t DoubleToFixedPoint(double d, int intBits, int fracBits);
+
+#endif // __FLTPOINT_H__
+
#CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2 -MMD
CFLAGS = -std=$(STD) -D_DEFAULT_SOURCE -g -D__GCCUNIX__ -I. -O2
-SRCS = 6502.c amode.c debug.c direct.c eagen.c error.c expr.c fltpoint.c listing.c mach.c macro.c mark.c object.c procln.c riscasm.c rmac.c sect.c symbol.c token.c
+SRCS = 6502.c amode.c debug.c direct.c eagen.c error.c expr.c fltpoint.c listing.c mach.c macro.c mark.c object.c op.c procln.c riscasm.c rmac.c sect.c symbol.c token.c
-OBJS = 6502.o amode.o debug.o direct.o eagen.o error.o expr.o fltpoint.o listing.o mach.o macro.o mark.o object.o procln.o riscasm.o rmac.o sect.o symbol.o token.o
+OBJS = 6502.o amode.o debug.o direct.o eagen.o error.o expr.o fltpoint.o listing.o mach.o macro.o mark.o object.o op.o procln.o riscasm.o rmac.o sect.o symbol.o token.o
#
# Build everything
#
-all : mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h rmac
+all : mntab.h 68ktab.h kwtab.h risckw.h 6502kw.h opkw.h rmac
@echo
@echo "Don't forget to bump the version number before commiting!"
@echo
risckw.h : kwtab kwgen
./kwgen mr <risctab >risckw.h
+opkw.h : op.tab kwgen
+ ./kwgen mo <op.tab >opkw.h
+
#
# Build tools
#
object.o : object.c object.h
$(CC) $(CFLAGS) -c object.c
+op.o : op.c op.h
+ $(CC) $(CFLAGS) -c op.c
+
procln.o : procln.c procln.h
$(CC) $(CFLAGS) -c procln.c
#
# Dependencies
#
-6502.o: 6502.c direct.h rmac.h symbol.h expr.h error.h mach.h procln.h \
- token.h riscasm.h sect.h
+6502.o: 6502.c direct.h rmac.h symbol.h token.h expr.h error.h mach.h \
+ procln.h riscasm.h sect.h
68kgen.o: 68kgen.c
amode.o: amode.c amode.h rmac.h symbol.h error.h expr.h mach.h procln.h \
token.h sect.h kwtab.h mntab.h parmode.h
-debug.o: debug.c debug.h rmac.h symbol.h amode.h direct.h mark.h sect.h \
- token.h
-direct.o: direct.c direct.h rmac.h symbol.h 6502.h amode.h error.h expr.h \
- listing.h mach.h macro.h mark.h procln.h token.h riscasm.h sect.h \
- kwtab.h fltpoint.h
-eagen.o: eagen.c eagen.h rmac.h symbol.h amode.h sect.h mark.h error.h \
- mach.h riscasm.h eagen0.c fltpoint.h
-error.o: error.c error.h rmac.h symbol.h token.h listing.h
-expr.o: expr.c expr.h rmac.h symbol.h direct.h error.h listing.h mach.h \
- procln.h token.h riscasm.h sect.h kwtab.h
+debug.o: debug.c debug.h rmac.h symbol.h amode.h direct.h token.h expr.h \
+ mark.h sect.h
+direct.o: direct.c direct.h rmac.h symbol.h token.h 6502.h amode.h \
+ error.h expr.h fltpoint.h listing.h mach.h macro.h mark.h procln.h \
+ riscasm.h sect.h kwtab.h
+eagen.o: eagen.c eagen.h rmac.h symbol.h amode.h error.h fltpoint.h \
+ mach.h mark.h riscasm.h sect.h token.h eagen0.c
+error.o: error.c error.h rmac.h symbol.h listing.h token.h
+expr.o: expr.c expr.h rmac.h symbol.h direct.h token.h error.h listing.h \
+ mach.h procln.h riscasm.h sect.h kwtab.h
+fltpoint.o: fltpoint.c fltpoint.h
kwgen.o: kwgen.c
listing.o: listing.c listing.h rmac.h symbol.h error.h procln.h token.h \
sect.h version.h
-mach.o: mach.c mach.h rmac.h symbol.h amode.h direct.h eagen.h error.h \
- procln.h token.h riscasm.h sect.h kwtab.h 68ktab.h
-macro.o: macro.c macro.h rmac.h symbol.h debug.h direct.h error.h expr.h \
- listing.h procln.h token.h
+mach.o: mach.c mach.h rmac.h symbol.h amode.h direct.h token.h eagen.h \
+ error.h expr.h procln.h riscasm.h sect.h kwtab.h 68ktab.h
+macro.o: macro.c macro.h rmac.h symbol.h debug.h direct.h token.h error.h \
+ expr.h listing.h procln.h
mark.o: mark.c mark.h rmac.h symbol.h error.h object.h riscasm.h sect.h
-object.o: object.c object.h rmac.h symbol.h 6502.h error.h mark.h \
- riscasm.h sect.h
+object.o: object.c object.h rmac.h symbol.h 6502.h direct.h token.h \
+ error.h mark.h riscasm.h sect.h
+op.o: op.c op.h rmac.h symbol.h direct.h token.h error.h expr.h \
+ fltpoint.h mark.h procln.h riscasm.h sect.h
procln.o: procln.c procln.h rmac.h symbol.h token.h 6502.h amode.h \
- direct.h error.h expr.h listing.h mach.h macro.h riscasm.h sect.h \
- kwtab.h mntab.h risckw.h 6502kw.h
-riscasm.o: riscasm.c riscasm.h rmac.h symbol.h amode.h direct.h error.h \
- expr.h mark.h procln.h token.h sect.h risckw.h kwtab.h
-rmac.o: rmac.c rmac.h symbol.h 6502.h debug.h direct.h error.h expr.h \
- listing.h mark.h macro.h object.h procln.h token.h riscasm.h sect.h \
+ direct.h error.h expr.h listing.h mach.h macro.h op.h riscasm.h sect.h \
+ kwtab.h mntab.h risckw.h 6502kw.h opkw.h
+riscasm.o: riscasm.c riscasm.h rmac.h symbol.h amode.h direct.h token.h \
+ error.h expr.h mark.h procln.h sect.h risckw.h kwtab.h
+rmac.o: rmac.c rmac.h symbol.h 6502.h debug.h direct.h token.h error.h \
+ expr.h listing.h mark.h macro.h object.h procln.h riscasm.h sect.h \
version.h
-sect.o: sect.c sect.h rmac.h symbol.h 6502.h direct.h error.h expr.h \
- listing.h mach.h mark.h riscasm.h token.h
+sect.o: sect.c sect.h rmac.h symbol.h 6502.h direct.h token.h error.h \
+ expr.h listing.h mach.h mark.h riscasm.h
symbol.o: symbol.c symbol.h error.h rmac.h listing.h object.h procln.h \
token.h
token.o: token.c token.h rmac.h symbol.h direct.h error.h macro.h \
uint32_t MarkRelocatable(uint16_t section, uint32_t loc, uint16_t to, uint16_t flags, SYM * symbol)
{
#ifdef DEBUG_IMAGE_MARKING
-printf("MarkRelocatable: section=%i, loc=$%X, to=$%X, flags=$%x, symbol=$%X\n", section, loc, to, flags, symbol);
+printf("MarkRelocatable: section=%i, loc=$%X, to=$%X, flags=$%x, symbol=%p\n", section, loc, to, flags, symbol);
if (symbol)
- printf(" symbol->stype=$%02X, sattr=$%04X, sattre=$%08X, svalue=%i, sname=%s\n", symbol->stype, symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
+ printf(" symbol->stype=$%02X, sattr=$%04X, sattre=$%08X, svalue=%li, sname=%s\n", symbol->stype, symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
#endif
if ((mcalloc - mcused) < MIN_MARK_MEM)
// This tells the linker to do a WORD relocation (otherwise it
// defaults to doing a LONG, throwing things off for WORD sized
// fixups)
- if (!(w & MLONG))
+ if (!(w & (MLONG | MQUAD)))
rflag |= 0x00000002;
+ // Tell the linker that the fixup is an OL QUAD data address
+ if (w & MQUAD)
+ rflag |= 0x00000004;
+
if (symbol != NULL)
{
// Deposit external reference
if (w & (DATA | BSS))
{
uint8_t * dp = objImage + BSDHDRSIZE + loc;
+ uint32_t olBitsSave = 0;
// Bump the start of the section if it's DATA (& not TEXT)
if (from == DATA)
dp += tsize;
uint32_t diff = (rflag & 0x02 ? GETBE16(dp, 0) : GETBE32(dp, 0));
+
+ // Special handling for OP (data addr) relocation...
+ if (rflag & 0x04)
+ {
+ olBitsSave = diff & 0x7FF;
+ diff = (diff & 0xFFFFF800) >> 8;
+ }
+
DEBUG printf("diff=%uX ==> ", diff);
#ifdef DEBUG_IMAGE_MARKING
-printf(" validsegment(4): diff = $%08X --> ", diff);
+printf(" validsegment(4): diff = $%08X ", diff);
#endif
if (rflag & 0x01)
diff = WORDSWAP32(diff);
+#ifdef DEBUG_IMAGE_MARKING
+printf("(sect[TEXT].sloc=$%X) --> ", sect[TEXT].sloc);
+#endif
diff += sect[TEXT].sloc;
if (w == BSS)
// thus leaving a naked semicolon afterwards to
// screw up the if/else structure. This is the price
// you pay when using macros pretending to be code.
- if (rflag & 0x02)
+ if (rflag & 0x02) // WORD relocation
{
SETBE16(dp, 0, diff);
}
- else
+ else if (rflag & 0x04) // OP data address relocation
+ {
+ // We do it this way because we might have an offset
+ // that is not a multiple of 8 and thus we need this in
+ // place to prevent a bad address at link time. :-P As
+ // a consequence of this, the highest address we can
+ // have here is $1FFFF8.
+ diff = ((diff & 0x001FFFFF) << 11) | olBitsSave;
+ SETBE32(dp, 0, diff);
+ }
+ else // LONG relocation
{
SETBE32(dp, 0, diff);
}
#define MWORD 0x0000 // Marked word
#define MLONG 0x0100 // Marked long
+#define MQUAD 0x0400 // Marked quad
//This will have to be defined eventually. Might have to overhaul the mark
//system as 8-bits doesn't seem to be enough, at least for a bitfield (which it
//might not have to be, in which case it would be big enough...)
//#define MQUAD 0x // Marked quad word (TODO: merge with MDOUBLE?)
#define MMOVEI 0x0200 // Mark RISC MOVEI instruction
-#define MDOUBLE 0x0400 // Marked double float
-#define MEXTEND 0x0800 // Marked extended float
-#define MSINGLE 0x0880 // Marked single float (TODO: merge with MLONG?)
+//#define MDOUBLE 0x0400 // Marked double float
+//#define MEXTEND 0x0800 // Marked extended float
+//#define MSINGLE 0x0880 // Marked single float (TODO: merge with MLONG?)
#define MGLOBAL 0x0800 // Mark contains global
#define MPCREL 0x1000 // Mark is PC-relative
#define MCHEND 0x2000 // Indicates end of mark chunk
nofpu 65
.opt 66
opt 66
+.objproc 67
-.if 500
-if 500
+.if 500
+if 500
.else 501
else 501
.endc 502
.endif 502
endif 502
.iif 503
-iif 503
+iif 503
.macro 504
macro 504
.endm 505
endr 507
.exitm 510
exitm 510
+
--- /dev/null
+//
+// Jaguar Object Processor assembler
+//
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "op.h"
+#include "direct.h"
+#include "error.h"
+#include "expr.h"
+#include "fltpoint.h"
+#include "mark.h"
+#include "procln.h"
+#include "riscasm.h"
+#include "rmac.h"
+#include "sect.h"
+#include "token.h"
+
+// Macros to help define things (though largely unnecessary for this assembler)
+#define BITMAP 3100
+#define SCBITMAP 3101
+#define GPUOBJ 3102
+#define BRANCH 3103
+#define STOP 3104
+#define NOP 3105
+#define JUMP 3106
+
+// Function prototypes
+int HandleBitmap(void);
+int HandleScaledBitmap(void);
+int HandleGPUObject(void);
+int HandleBranch(void);
+int HandleStop(void);
+int HandleNOP(void);
+int HandleJump(void);
+
+// OP assembler vars.
+static uint8_t lastObjType;
+static uint32_t lastSloc;
+static char scratchbuf[4096];
+static TOKEN fixupExpr[4] = { CONST, 0, 0, ENDEXPR };
+//static PTR fixupPtr = { .tk = (fixupExpr + 1) }; // C99 \o/
+static PTR fixupPtr = { (uint8_t *)(fixupExpr + 1) }; // meh, it works
+
+
+//
+// The main Object Processor assembler. Basically just calls the sub functions
+// to generate the appropriate code.
+//
+int GenerateOPCode(int state)
+{
+ if (!robjproc)
+ return error("opcode only valid in OP mode");
+
+ switch (state)
+ {
+ case BITMAP:
+ return HandleBitmap();
+ case SCBITMAP:
+ return HandleScaledBitmap();
+ case GPUOBJ:
+ return HandleGPUObject();
+ case BRANCH:
+ return HandleBranch();
+ case STOP:
+ return HandleStop();
+ case NOP:
+ return HandleNOP();
+ case JUMP:
+ return HandleJump();
+ }
+
+ return error("unknown OP opcode");
+}
+
+
+static inline void GetSymbolUCFromTokenStream(char * s)
+{
+ strcpy(s, string[tok[1]]);
+ strtoupper(s);
+ tok += 2;
+}
+
+
+static inline uint64_t CheckFlags(char * s)
+{
+ GetSymbolUCFromTokenStream(s);
+
+ if (strcmp(scratchbuf, "REFLECT") == 0)
+ return 0x01;
+ else if (strcmp(scratchbuf, "RMW") == 0)
+ return 0x02;
+ else if (strcmp(scratchbuf, "TRANS") == 0)
+ return 0x04;
+ else if (strcmp(scratchbuf, "RELEASE") == 0)
+ return 0x08;
+ return 0;
+}
+
+
+//
+// Define a bitmap object
+// Form: bitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>, <bpp>,
+// <pallete idx>, <flags>, <firstpix>, <pitch>
+//
+int HandleBitmap(void)
+{
+ uint64_t xpos = 0;
+ uint64_t ypos = 0;
+ uint64_t iheight = 0;
+ uint64_t dwidth = 0;
+ uint64_t iwidth = 0;
+ uint64_t bpp = 0;
+ uint64_t index = 0;
+ uint64_t flags = 0;
+ uint64_t firstpix = 0;
+ uint64_t pitch = 1;
+
+ uint64_t eval;
+ uint16_t eattr;
+ SYM * esym = 0;
+
+ if ((orgaddr & 0x0F) != 0)
+ {
+ warn("bitmap not on double phrase boundary");
+
+ // Fixup org address (by emitting a NOP)...
+ HandleNOP();
+
+ // We don't need to do a fixup here, because we're guaranteed that the
+ // last object, if it was a scaled bitmap *or* regular bitmap, will
+ // already be on the correct boundary, so we won't have to fix it up.
+ }
+
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
+ else if (eattr & TDB)
+ MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
+
+ uint64_t dataAddr = eval & 0xFFFFF8;
+ uint64_t linkAddr = (orgaddr + 16) & 0x3FFFF8;
+
+ uint64_t * vars[10] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &bpp, &index, 0, &firstpix, &pitch };
+
+ for(int i=0; i<10; i++)
+ {
+ // If there are less than 10 arguments after the data address, use
+ // defaults for the rest of them
+ // N.B.: Should there be a default minimum # of args? Like the first 5?
+ if (tok[0] == EOL)
+ break;
+
+ CHECK_COMMA;
+
+ if (i != 7)
+ {
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ return error("bad expression");
+
+ *vars[i] = eval;
+ }
+ else
+ {
+ // Handle FLAGs. Can have at most four.
+ for(int j=0; j<4; j++)
+ {
+ if (tok[0] != SYMBOL)
+ return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
+
+ flags |= CheckFlags(scratchbuf);
+
+ // Break out if no more symbols...
+ if (tok[0] != SYMBOL)
+ break;
+ }
+ }
+ }
+
+ at_eol();
+
+ uint64_t p1 = 0x00 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
+ uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
+
+ lastSloc = sloc;
+ lastObjType = 0;
+ D_quad(p1);
+ D_quad(p2);
+
+ return OK;
+}
+
+
+//
+// Define a scaled bitmap object
+// Form: scbitmap <data>, <xloc>, <yloc>, <dwidth>, <iwidth>, <iheight>,
+// <xscale>, <yscale>, <remainder>, <bpp>, <pallete idx>,
+// <flags>, <firstpix>, <pitch>
+//
+int HandleScaledBitmap(void)
+{
+ uint64_t xpos = 0;
+ uint64_t ypos = 0;
+ uint64_t iheight = 0;
+ uint64_t dwidth = 0;
+ uint64_t iwidth = 0;
+ uint64_t bpp = 0;
+ uint64_t index = 0;
+ uint64_t flags = 0;
+ uint64_t firstpix = 0;
+ uint64_t pitch = 1;
+ uint64_t xscale = 0;
+ uint64_t yscale = 0;
+ uint64_t remainder = 0;
+
+ uint64_t eval;
+ uint16_t eattr;
+ SYM * esym = 0;
+
+ if ((orgaddr & 0x1F) != 0)
+ {
+ warn("scaled bitmap not on quad phrase boundary");
+
+ // We only have to do a fixup here if the previous object was a bitmap,
+ // as it can live on a 16-byte boundary while scaled bitmaps can't. If
+ // the previous object was a scaled bitmap, it is guaranteed to have
+ // been aligned, therefore no fixup is necessary.
+ if (lastObjType == 0)
+ {
+ *fixupPtr.u64 = (orgaddr + 0x18) & 0xFFFFFFE0;
+ AddFixup(FU_QUAD | FU_OBJLINK, lastSloc, fixupExpr);
+ }
+
+ switch (orgaddr & 0x1F)
+ {
+ case 0x08: HandleNOP(); // Emit 3 NOPs
+ case 0x10: HandleNOP(); // Emit 2 NOPs
+ case 0x18: HandleNOP(); // Emit 1 NOP
+ }
+ }
+
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ AddFixup(FU_QUAD | FU_OBJDATA, sloc, exprbuf);
+ else if (eattr & TDB)
+ MarkRelocatable(cursect, sloc, (eattr & TDB), MQUAD, NULL);
+
+ uint64_t dataAddr = eval & 0xFFFFF8;
+ uint64_t linkAddr = (orgaddr + 32) & 0x3FFFF8;
+
+ uint64_t * vars[13] = { &xpos, &ypos, &dwidth, &iwidth, &iheight, &xscale, &yscale, &remainder, &bpp, &index, 0, &firstpix, &pitch };
+
+ for(int i=0; i<13; i++)
+ {
+ // If there are less than 13 arguments after the data address, use
+ // defaults for the rest of them
+ // N.B.: Should there be a default minimum # of args? Like the first 5?
+ if (tok[0] == EOL)
+ break;
+
+ CHECK_COMMA;
+
+ if (i != 10)
+ {
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ return error("bad expression");
+
+ // Handle 3.5 fixed point nums (if any)...
+ if ((i >= 5) && (i <= 7))
+ {
+ if (eattr & FLOAT) // Handle floats
+ {
+// PTR p = { .u64 = &eval }; // C99 \o/
+ PTR p = { (uint8_t *)&eval }; // Meh, it works
+ eval = DoubleToFixedPoint(*p.dp, 3, 5);
+ }
+ else
+ eval <<= 5; // Otherwise, it's just an int...
+ }
+
+ *vars[i] = eval;
+ }
+ else
+ {
+ // Handle FLAGs. Can have at most four.
+ for(int j=0; j<4; j++)
+ {
+ if (tok[0] != SYMBOL)
+ return error("missing REFLECT, RMW, TRANS, and/or RELEASE");
+
+ flags |= CheckFlags(scratchbuf);
+
+ // Break out if no more symbols...
+ if (tok[0] != SYMBOL)
+ break;
+ }
+ }
+ }
+
+ at_eol();
+
+ uint64_t p1 = 0x01 | ((ypos * 2) << 3) | (iheight << 14) | (linkAddr << 21) | (dataAddr << 40);
+ uint64_t p2 = xpos | (bpp << 12) | (pitch << 15) | (dwidth << 18) | (iwidth << 28) | (index << 38) | (flags << 45) | (firstpix << 49);
+ uint64_t p3 = (xscale & 0xFF) | (yscale & 0xFF) << 8 | (remainder & 0xFF) << 16;
+
+ lastSloc = sloc;
+ lastObjType = 1;
+ D_quad(p1);
+ D_quad(p2);
+ D_quad(p3);
+ D_quad(0LL);
+
+ return OK;
+}
+
+
+//
+// Insert GPU object
+// Form: gpuobj <line #>, <userdata> (bits 14-63 of this object)
+//
+int HandleGPUObject(void)
+{
+ uint64_t eval;
+ uint16_t eattr;
+ SYM * esym = 0;
+
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ return error("bad expression in y position");
+
+ uint64_t ypos = eval;
+
+ CHECK_COMMA;
+
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ return error("bad expression in data");
+
+ at_eol();
+
+ uint64_t p1 = 0x02 | ((ypos * 2) << 3) | (eval << 14);
+
+ lastObjType = 2;
+ D_quad(p1);
+
+ return OK;
+}
+
+
+//
+// Insert a branch object
+// Form: branch VC <condition (<, =, >)> <line #>, <link addr>
+// branch OPFLAG, <link addr>
+// branch SECHALF, <link addr>
+//
+int HandleBranch(void)
+{
+ char missingKeyword[] = "missing VC, OPFLAG, or SECHALF in branch";
+ uint32_t cc = 0;
+ uint32_t ypos = 0;
+ uint64_t eval;
+ uint16_t eattr;
+ SYM * esym = 0;
+
+ if (tok[0] != SYMBOL)
+ return error(missingKeyword);
+
+ GetSymbolUCFromTokenStream(scratchbuf);
+
+ if (strcmp(scratchbuf, "VC") == 0)
+ {
+ switch (*tok++)
+ {
+ case '=': cc = 0; break;
+ case '<': cc = 1; break;
+ case '>': cc = 2; break;
+ default:
+ return error("missing '<', '>', or '='");
+ }
+
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ return error("bad expression");
+
+ ypos = (uint32_t)eval;
+ }
+ else if (strcmp(scratchbuf, "OPFLAG") == 0)
+ cc = 3;
+ else if (strcmp(scratchbuf, "SECHALF") == 0)
+ cc = 4;
+ else
+ return error(missingKeyword);
+
+ CHECK_COMMA;
+
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
+
+ at_eol();
+
+ uint64_t p1 = 0x03 | (cc << 14) | ((ypos * 2) << 3) | ((eval & 0x3FFFF8) << 21);
+
+ lastObjType = 3;
+ D_quad(p1);
+
+ return OK;
+}
+
+
+//
+// Insert a stop object
+// Form: stop
+//
+int HandleStop(void)
+{
+ lastObjType = 4;
+ D_quad(4LL);
+
+ return OK;
+}
+
+
+//
+// Insert a phrase sized "NOP" in the object list (psuedo-op)
+// Form: nop
+//
+int HandleNOP(void)
+{
+ uint64_t eval = (orgaddr + 8) & 0x3FFFF8;
+ // This is "branch if VC > 2047". Branch addr is next phrase, so either way
+ // it will pass by this phrase.
+ uint64_t p1 = 0x03 | (2 << 14) | (0x7FF << 3) | (eval << 21);
+
+ lastObjType = 3;
+ D_quad(p1);
+
+ return OK;
+}
+
+
+//
+// Insert an unconditional jump in the object list (psuedo-op)
+// Form: jump <link addr>
+//
+int HandleJump(void)
+{
+ uint64_t eval;
+ uint16_t eattr;
+ SYM * esym = 0;
+
+ if (expr(exprbuf, &eval, &eattr, &esym) != OK)
+ return ERROR;
+
+ if (!(eattr & DEFINED))
+ AddFixup(FU_QUAD | FU_OBJLINK, sloc, exprbuf);
+
+ at_eol();
+
+ // This is "branch if VC < 2047", which pretty much guarantees the branch.
+ uint64_t p1 = 0x03 | (1 << 14) | (0x7FF << 3) | ((eval & 0x3FFFF8) << 21);
+
+ lastObjType = 3;
+ D_quad(p1);
+
+ return OK;
+}
+
--- /dev/null
+//
+// Object Processor assembler
+//
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#ifndef __OP_H__
+#define __OP_H__
+
+// Exported functions
+int GenerateOPCode(int);
+
+#endif // __OP_H__
+
--- /dev/null
+#
+# Jaguar Object Processor mnemonics
+#
+bitmap 3100
+scbitmap 3101
+gpuobj 3102
+branch 3103
+stop 3104
+nop 3105
+jump 3106
+
#include "listing.h"
#include "mach.h"
#include "macro.h"
+#include "op.h"
#include "riscasm.h"
#include "sect.h"
#include "symbol.h"
#define DECL_MP // Include 6502 keyword state machine tables
#include "6502kw.h"
+#define DEF_MO // Include OP keyword definitions
+#define DECL_MO // Include OP keyword state machine tables
+#include "opkw.h"
+
IFENT * ifent; // Current ifent
static IFENT ifent0; // Root ifent
IFENT * f_ifent; // Freelist of ifents
}
}
+ // If we are in OP mode and still in need of a mnemonic then search for one
+ if (robjproc && ((state < 0) || (state >= 1000)))
+ {
+ for(state=0, p=opname; state>=0;)
+ {
+ j = mobase[state] + (int)tolowertab[*p];
+
+ // Reject, character doesn't match
+ if (mocheck[j] != state)
+ {
+ state = -1; // No match
+ break;
+ }
+
+ // Must accept or reject at EOS
+ if (!*++p)
+ {
+ state = moaccept[j]; // (-1 on no terminal match)
+ break;
+ }
+
+ state = motab[j];
+ }
+
+ // Call OP code generator if we found a mnemonic
+ if (state >= 3100)
+ {
+ GenerateOPCode(state);
+ goto loop;
+ }
+ }
+
// Invoke macro or complain about bad mnemonic
if (state < 0)
{
#include "expr.h"
#include "mark.h"
#include "procln.h"
+#include "rmac.h"
#include "sect.h"
#include "token.h"
};
-//
-// Convert a string to uppercase
-//
-static void strtoupper(char * s)
-{
- while (*s)
- *s++ &= 0xDF;
-}
-
-
//
// Function to return "malformed expression" error
// This is done mainly to remove a bunch of GOTO statements in the parser
#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); }
+#define CHECK_COMMA if (*tok++ != ',') { return error(comma_error); }
// Globals, externals etc
extern unsigned orgactive;
int err_flag; // '-e' specified
int err_fd; // File to write error messages to
int rgpu, rdsp; // Assembling Jaguar GPU or DSP code
+int robjproc; // Assembling Jaguar Object Processor code
int dsp56001; // Assembling DSP 56001 code
int list_fd; // File to write listing to
int regbank; // RISC register bank
int activefpu = FPU_NONE; // Active FPU (none by default)
+//
+// Convert a string to uppercase
+//
+void strtoupper(char * s)
+{
+ while (*s)
+ *s++ &= 0xDF;
+}
+
+
//
// Manipulate file extension.
//
err_flag = 0; // Initialise error flag
rgpu = 0; // Initialise GPU assembly flag
rdsp = 0; // Initialise DSP assembly flag
+ robjproc = 0; // Initialise OP 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
extern int verb_flag;
extern int debug;
extern int rgpu, rdsp;
+extern int robjproc;
extern int dsp56001;
extern int err_flag;
extern int err_fd;
extern int activefpu;
// Exported functions
+void strtoupper(char * s);
char * fext(char *, char *, int);
int nthpath(char *, int, char *);
int ParseOptimization(char * optstring);
DEBUG { printf("AddFixup: sno=%u, l#=%u, attr=$%X, loc=$%X, expr=%p, sym=%p, org=$%X\n", cursect, fixup->lineno, fixup->attr, fixup->loc, (void *)fixup->expr, (void *)fixup->symbol, fixup->orgaddr);
if (symbol != NULL)
- printf(" name: %s, value: $lX\n", symbol->sname, symbol->svalue);
+ printf(" name: %s, value: $%lX\n", symbol->sname, symbol->svalue);
}
return 0;
break;
- // Fixup LONG forward references;
- // the long could be unaligned in the section buffer, so be careful
- // (again).
+ // Fixup LONG forward references; the long could be unaligned in the
+ // section buffer, so be careful (again).
case FU_LONG:
flags = MLONG;
SETBE32(locp, 0, eval);
break;
+ // Fixup QUAD forward references
+ // Need to add flags for OP uses... [DONE]
+ case FU_QUAD:
+ // If the symbol is undefined, make sure to pass the symbol in
+ // to the MarkRelocatable() function.
+/* if (!(eattr & DEFINED))
+ MarkRelocatable(sno, loc, 0, MQUAD, esym);
+ else if (tdb)
+ MarkRelocatable(sno, loc, tdb, MQUAD, NULL);//*/
+
+ if (w & FU_OBJLINK)
+ {
+ uint64_t quad = GETBE64(locp, 0);
+ uint64_t addr = eval;
+
+ if (fup->orgaddr)
+ addr = fup->orgaddr;
+
+//printf("sect.c: FU_OBJLINK quad=%016lX, addr=%016lX ", quad, addr);
+
+ eval = (quad & 0xFFFFFC0000FFFFFFLL) | ((addr & 0x3FFFF8) << 21);
+//printf("(%016lX)\n", eval);
+ }
+ else if (w & FU_OBJDATA)
+ {
+ uint64_t quad = GETBE64(locp, 0);
+ uint64_t addr = eval;
+
+ if (fup->orgaddr)
+ addr = fup->orgaddr;
+
+ eval = (quad & 0x000007FFFFFFFFFFLL) | ((addr & 0xFFFFF8) << 40);
+ }
+
+ SETBE64(locp, 0, eval);
+//printf("(%016lX)\n", 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:
#define FU_6BRA 0x0007 // Fixup 6502-format branch offset
#define FU_BYTEH 0x0008 // Fixup 6502 high byte of immediate word
#define FU_BYTEL 0x0009 // Fixup 6502 low byte of immediate word
+#define FU_QUAD 0x000A // Fixup quad-word (8 bytes)
#define FU_SEXT 0x0010 // Ok to sign extend
#define FU_PCREL 0x0020 // Subtract PC first
#define FU_DONE 0x8000 // Fixup has been done
// FPU fixups
-#define FU_FLOATSING 0x000A // Fixup 32-bit float
-#define FU_FLOATDOUB 0x000B // Fixup 64-bit float
-#define FU_FLOATEXT 0x000C // Fixup 96-bit float
+#define FU_FLOATSING 0x000B // Fixup 32-bit float
+#define FU_FLOATDOUB 0x000C // Fixup 64-bit float
+#define FU_FLOATEXT 0x000D // Fixup 96-bit float
+
+// OP fixups
+#define FU_OBJLINK 0x10000 // Fixup OL link addr (bits 24-42, drop last 3)
+#define FU_OBJDATA 0x20000 // Fixup OL data addr (bits 43-63, drop last 3)
+
// Chunks are used to hold generated code and fixup records
#define CHUNK struct _chunk
// Release Information
#define MAJOR 1 // Major version number
-#define MINOR 12 // Minor version number
-#define PATCH 5 // Patch release number
+#define MINOR 13 // Minor version number
+#define PATCH 0 // Patch release number
#endif // __VERSION_H__