From 261f8d9198c4235bcdced4403ba391553e6bd0d1 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Sun, 25 Feb 2018 21:39:59 -0600 Subject: [PATCH] Added Jaguar Object Processor assembler. Rationale for this and how it works can be found in docs/note-on-the-op-assembler.txt. Version now at 1.13.0. --- .gitignore | 2 + direct.c | 71 ++++- docs/note-on-the-op-assembler.txt | 129 ++++++++ eagen0.c | 15 +- fltpoint.c | 23 ++ fltpoint.h | 9 +- makefile | 67 ++-- mark.c | 38 ++- mark.h | 7 +- mntab | 8 +- op.c | 487 ++++++++++++++++++++++++++++++ op.h | 15 + op.tab | 11 + procln.c | 37 +++ riscasm.c | 11 +- riscasm.h | 2 +- rmac.c | 12 + rmac.h | 2 + sect.c | 45 ++- sect.h | 12 +- version.h | 4 +- 21 files changed, 924 insertions(+), 83 deletions(-) create mode 100644 docs/note-on-the-op-assembler.txt create mode 100644 op.c create mode 100644 op.h create mode 100644 op.tab diff --git a/.gitignore b/.gitignore index be2b8f8..8266a9c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ 68kgen.o 68ktab.h 68kmn +6502kw.h +opkw.h *.o *~ kwtab.h diff --git a/direct.c b/direct.c index 9e39719..2511473 100644 --- a/direct.c +++ b/direct.c @@ -79,6 +79,7 @@ int d_cstruct(void); int d_prgflags(void); int d_opt(void); int d_dsp(void); +int d_objproc(void); void SetLargestAlignment(int); // Directive handler table @@ -149,7 +150,8 @@ int (*dirtab[])() = { d_68882, // 63 .68882 d_56001, // 64 .56001 d_nofpu, // 65 nofpu - d_opt, // 58 .opt + d_opt, // 66 .opt + d_objproc, // 67 .objproc }; @@ -216,8 +218,8 @@ int d_org(void) { 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) { @@ -225,7 +227,7 @@ int d_org(void) return ERROR; } - if (rgpu | rdsp) + if (rgpu | rdsp | robjproc) { orgaddr = address; orgactive = 1; @@ -1066,9 +1068,6 @@ int d_dc(WORD siz) uint16_t tdb = eattr & TDB; uint16_t defined = eattr & DEFINED; - if ((challoc - ch_size) < 4) - chcheck(4); - switch (siz) { case SIZB: @@ -1136,6 +1135,7 @@ int d_dc(WORD siz) D_long(eval); } + break; case SIZQ: // 64-bit size @@ -1144,7 +1144,17 @@ int d_dc(WORD siz) // 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 @@ -1158,8 +1168,9 @@ int d_dc(WORD siz) } 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; @@ -1180,8 +1191,9 @@ int d_dc(WORD siz) } 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; @@ -1204,8 +1216,9 @@ int d_dc(WORD siz) } 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; @@ -1483,7 +1496,7 @@ int d_nlist(void) // 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; @@ -1601,6 +1614,7 @@ int d_gpu(void) 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; } @@ -1626,6 +1640,7 @@ int d_dsp(void) 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; } @@ -1876,6 +1891,32 @@ int d_cstruct(void) } +// +// 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...] // diff --git a/docs/note-on-the-op-assembler.txt b/docs/note-on-the-op-assembler.txt new file mode 100644 index 0000000..8a3d14b --- /dev/null +++ b/docs/note-on-the-op-assembler.txt @@ -0,0 +1,129 @@ +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 , , , , , , , + , , , + scbitmap , , , , , , + , , , , , + , , + gpuobj , (bits 14-63 of this object) + branch VC )> , + branch OPFLAG, + branch SECHALF, + stop + nop + jump + + Note that the 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 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 , , and fields can be + floating point constants/expressions. 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 + diff --git a/eagen0.c b/eagen0.c index 1bc5fd6..5b3c4ab 100644 --- a/eagen0.c +++ b/eagen0.c @@ -214,8 +214,9 @@ int eaNgen(WORD siz) // 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 @@ -238,8 +239,9 @@ int eaNgen(WORD siz) // 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; @@ -258,8 +260,9 @@ int eaNgen(WORD siz) // 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; diff --git a/fltpoint.c b/fltpoint.c index fa1eb41..911e008 100644 --- a/fltpoint.c +++ b/fltpoint.c @@ -14,6 +14,7 @@ #include "fltpoint.h" #include #include +#include // // Check for IEEE-754 conformance (C99 compilers should be OK here) @@ -169,3 +170,25 @@ void DoubleToExtended(double d, uint8_t out[]) 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; +} + diff --git a/fltpoint.h b/fltpoint.h index c3d4038..558ad7b 100644 --- a/fltpoint.h +++ b/fltpoint.h @@ -1,13 +1,20 @@ // -// 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 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__ + diff --git a/makefile b/makefile index 997e2bc..f966ea1 100644 --- a/makefile +++ b/makefile @@ -27,15 +27,15 @@ HOSTCC = gcc #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 @@ -61,6 +61,9 @@ kwtab.h : kwtab kwgen risckw.h : kwtab kwgen ./kwgen mr risckw.h +opkw.h : op.tab kwgen + ./kwgen mo opkw.h + # # Build tools # @@ -120,6 +123,9 @@ mark.o : mark.c mark.h 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 @@ -151,41 +157,44 @@ clean: # # 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 \ diff --git a/mark.c b/mark.c index 53eaf87..ca7152e 100644 --- a/mark.c +++ b/mark.c @@ -71,9 +71,9 @@ void StopMark(void) 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) @@ -380,9 +380,13 @@ printf(" validsegment: raddr = $%08X\n", loc); // 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 @@ -415,19 +419,31 @@ printf(" validsegment(3): rflag = $%08X\n", rflag); 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) @@ -442,11 +458,21 @@ printf(" validsegment(4): diff = $%08X --> ", diff); // 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); } diff --git a/mark.h b/mark.h index 5e97d8a..2415a80 100644 --- a/mark.h +++ b/mark.h @@ -26,14 +26,15 @@ MCHUNK { #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 diff --git a/mntab b/mntab index b65271a..3355dfe 100644 --- a/mntab +++ b/mntab @@ -110,9 +110,10 @@ prgflags 57 nofpu 65 .opt 66 opt 66 +.objproc 67 -.if 500 -if 500 +.if 500 +if 500 .else 501 else 501 .endc 502 @@ -120,7 +121,7 @@ endc 502 .endif 502 endif 502 .iif 503 -iif 503 +iif 503 .macro 504 macro 504 .endm 505 @@ -131,3 +132,4 @@ rept 506 endr 507 .exitm 510 exitm 510 + diff --git a/op.c b/op.c new file mode 100644 index 0000000..f0ec970 --- /dev/null +++ b/op.c @@ -0,0 +1,487 @@ +// +// 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 , , , , , , , +// , , , +// +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 , , , , , , +// , , , , , +// , , +// +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 , (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 )> , +// branch OPFLAG, +// branch SECHALF, +// +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 +// +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; +} + diff --git a/op.h b/op.h new file mode 100644 index 0000000..f7c31b8 --- /dev/null +++ b/op.h @@ -0,0 +1,15 @@ +// +// Object Processor assembler +// +// by James Hammons +// (C) 2018 Underground Software +// + +#ifndef __OP_H__ +#define __OP_H__ + +// Exported functions +int GenerateOPCode(int); + +#endif // __OP_H__ + diff --git a/op.tab b/op.tab new file mode 100644 index 0000000..cdbc8eb --- /dev/null +++ b/op.tab @@ -0,0 +1,11 @@ +# +# Jaguar Object Processor mnemonics +# +bitmap 3100 +scbitmap 3101 +gpuobj 3102 +branch 3103 +stop 3104 +nop 3105 +jump 3106 + diff --git a/procln.c b/procln.c index addff04..eb74281 100644 --- a/procln.c +++ b/procln.c @@ -15,6 +15,7 @@ #include "listing.h" #include "mach.h" #include "macro.h" +#include "op.h" #include "riscasm.h" #include "sect.h" #include "symbol.h" @@ -34,6 +35,10 @@ #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 @@ -659,6 +664,38 @@ When checking to see if it's already been equated, issue a warning. } } + // 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) { diff --git a/riscasm.c b/riscasm.c index d595ebc..0b09bf1 100644 --- a/riscasm.c +++ b/riscasm.c @@ -13,6 +13,7 @@ #include "expr.h" #include "mark.h" #include "procln.h" +#include "rmac.h" #include "sect.h" #include "token.h" @@ -134,16 +135,6 @@ static const char * malformErr[] = { }; -// -// 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 diff --git a/riscasm.h b/riscasm.h index 560726c..91376dc 100644 --- a/riscasm.h +++ b/riscasm.h @@ -32,7 +32,7 @@ #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; diff --git a/rmac.c b/rmac.c index 21e1fb8..199cff7 100644 --- a/rmac.c +++ b/rmac.c @@ -40,6 +40,7 @@ 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 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 @@ -55,6 +56,16 @@ int activecpu = CPU_68000; // Active 68k CPU (68000 by default) 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. // @@ -271,6 +282,7 @@ int Process(int argc, char ** argv) 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 diff --git a/rmac.h b/rmac.h index 07d6ed1..f282460 100644 --- a/rmac.h +++ b/rmac.h @@ -284,6 +284,7 @@ enum 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; @@ -306,6 +307,7 @@ extern int activecpu; extern int activefpu; // Exported functions +void strtoupper(char * s); char * fext(char *, char *, int); int nthpath(char *, int, char *); int ParseOptimization(char * optstring); diff --git a/sect.c b/sect.c index 2269403..5d7fb4a 100644 --- a/sect.c +++ b/sect.c @@ -290,7 +290,7 @@ int AddFixup(uint32_t attr, uint32_t loc, TOKEN * fexpr) 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; @@ -679,9 +679,8 @@ int ResolveFixups(int sno) 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; @@ -702,6 +701,44 @@ int ResolveFixups(int sno) 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: diff --git a/sect.h b/sect.h index dc5e167..11ddfd4 100644 --- a/sect.h +++ b/sect.h @@ -76,6 +76,7 @@ #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 @@ -98,9 +99,14 @@ #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 diff --git a/version.h b/version.h index b56b49a..66de9ac 100644 --- a/version.h +++ b/version.h @@ -14,8 +14,8 @@ // 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__ -- 2.37.2