This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

MagicKit assembler new unofficial version

MagicKit assembler new unofficial version
by on (#97318)
Here is new unofficial version of MagicKit with new features. (Some people don't like MagicKit/NESASM but I like it.) Please tell me if I missed anything.

It is included with PPMCK: http://zzo38computer.org/nes_program/ppmck.zip

Document of new features is file EXTENSION.TXT which is also copied here:
Code:
This is document to describe unofficial extensions of MagicKit assembler.

Status ask expression:
  ?A   bank base index
  ?B   current bank
  ?C   current section
  ?D   data location counter
  ?E   error counter
  ?L   location counter
  ?M   map data at current location
  ?P   page
  ?Q   pseudopage
  ?R   RS counter
  ?S   source line number
  ?X   pass counter (0=first pass, 1=last pass)
  ?Z   max bank used

Emulator I/O ($2000..$3FFF):
  $2000  RW    Bank number
  $2001  R     Error counter
  $2002  RW    Location counter low byte
  $2003  RW    Location counter high byte
  $2004  RW    Section (0=ZP, 1=BSS, 2=CODE, 3=DATA, 4=EMU)
  $2005   W    Send byte to output file
  $2006  RW    Bank output length low byte
  $2007  RW    Bank output length high byte
  $2008   W    Send contents of ROM bank to output file
  $2009  R     Maximum bank used
  $200A  RW    Standard I/O
  $200B  RW    Read next byte of data file (write anything for next file)
  $200C  RW    Read to test EOF of data file, write to rewind file
  $200D  RW    Address increment amount
  $200E  RW    Low byte of address
  $200F  RW    High byte of address
  $2010  RW    Data at address
  $2011  RW    Map data at address
  $2012  RW    Data at address, postincrement address
  $2013  RW    Map at address, postincrement address
  $2014   W    Write location counter in decimal to output file
  $2015   W    Compile a line of input in FIRST PASS mode
  $2016   W    Compile a line of input in LAST PASS mode

Instructions (NES/Famicom):
  ANC          AND accumulator by immediate and carry bit7
  ALR          AND accumulator by immediate and shift right
  ARR          AND accumulator by immediate and rotate right
  AXS          AND X register by accumulator and subtract immediate
  DCP          Decrement memory and compare with accumulator
  HLT          Jam the computer (until resets)
  ISC          Increment memory and subtract from accumulator
  JAM          Jam the computer (until resets)
  KIL          Jam the computer (until resets)
  LAX          Load into accumulator and into X register
  RLA          Left rotate memory and AND accumulator by memory
  RRA          Right rotate memory and add memory to accumulator
  SAX          Store value of accumulator AND X register
  SLO          Left shift memory and OR accumulator by memory
  SRE          Right shift memory and XOR accumulator by memory

Pseudos:
  .ASSIGN      Update value of reserved symbols
  .DATAFILE    Load extra data file
  .EMU         Select emulator memory section
  .MACGOTO     Tail call to another macro keeping same parameters
  .MACSET      Modify macro arguments

Pseudos (NES 2.0):
  .NES2CHRRAM  Set amount of CHR RAM (non-battery, battery)
  .NES2PRGRAM  Set amount of PRG RAM (non-battery, battery)
  .NES2SUB     Submapper number
  .NES2TV      TV mode (0=NTSC, 1=PAL, 2=both)
  .NES2VS      Vs. Unisystem mode

Macro special parameters:
  \\   backslash
  \@   unique five-digit number for each call of a macro
  \#   number of arguments
  \1   read argument
  \?1  read type of argument
  \<1  first character of argument only
  \>1  argument except first character
  \$1  length of argument

Command-line switch:
  -.nes    Select NES/Famicom machine type
  -.pce    Select PC-Engine machine type
  -o #     Override output filename
  -M       Create map file


== Use of .MACGOTO and .MACSET ==

You can use .MACGOTO command followed by a name of a macro (no quotation
marks) to call that macro with the same parameters as the current macro,
and is tail call so it will not continue with the current macro after that
one is finished. If you use it with conditions it could make a loop. You
can also adjust the parameter of .MACGOTO by .MACSET as well. Note: \@ is
not incremented if .MACGOTO is used.

The command .MACSET is followed by three numbers (or expressions)
delimited by commas. The first is the parameter number 1 to 9. Second is a
mode. Third parameter depend on the mode. The selected parameter value
will be changed for the current macro and affects subsequent commands and
.MACGOTO calls.

Mode 1: Copy argument inside of called macro. The third parameter is a
parameter number (1 to 9) and whatever macro has been called from inside
of this one, a parameter given to it, will be copied to this macro.

Mode 2: Copy argument of current macro. Third parameter is the parameter
number and it copy to another slot of the same macro.

Mode 3: Single character. The parameter will become a single character,
with the third parameter specifying the ASCII code of the character.

Mode 4: Numeric. Third parameter is evaluated and converted to a decimal
number which is placed in the macro arguments.

Mode 5: Cut off string. Third parameter is maximum number of characters to
keep from beginning of parameter string.

Mode 6: ASCII code at position. Third parameter is position. The parameter
is use as string, character at specified position, is converted to number
of ASCII. If the string is shorter than that, the result is zero.

Mode 7: Set and increment mcounter (the \@ counter). Third parameter is
the amount to increase by.

Mode 8: Read one byte of data from the current ROM bank.

Mode 9: Get a bank name, using third parameter as the bank number.

Mode 10: Read one byte of data from the map area for current ROM bank.

Mode 11: Read the macro argument from standard input.

Mode 12: Change the current nesting level for IF blocks. Second parameter
is amount of adjustment, and third parameter is nonzero to skip lines. The
resulting value will be the old nesting level.

Other modes currently have no use.


== Use of .ASSIGN ==

Syntax:  .ASSIGN "name" value

The name is a name in quotation marks and the value can be any expression.
Do not include a comma between the name and value.

This makes a reserved symbol and assign a value. You can assign different
values in different parts of the input file more than once, unlike the
ordinary labels.

It runs in both passes, in the order specified in input file, and you can
use the old value of the symbol to calculate the next value, too.


== Use of emulator ==

Unofficial MagicKit includes an emulator for use as a postprocessor. Note
that unofficial opcodes cannot be used, except for HLT.

If you put .EMU to assemble emulator codes and data in the emulator memory
map, which is 64K bytes, except for $2000..$3FFF for I/O, $4000..$5FFF for
data of active ROM bank (can be written as well), and $6000..$7FFF for map
data of ROM bank.

Inside of .EMU section use .ORG to specify where in the emulator RAM to
enter data (bank/page is not used in emulator RAM).

If the reset vector of the emulator is nonzero, it will run the emulator
after both passes of assembler, before writing output binary file. If you
write .EMU X at the start of .EMU block then it will use the emulator code
to write the binary file instead of using the normal way. (If .EMU X is
used but does not write to $2005 and $2008 then you will get empty output
file.)

Use HLT command to stop the emulator.

Emulation is done by lib6502, with a modification to suppress the error
message for illegal opcodes.


== Counted labels ==

Counted labels are given by making a label starting with / and optionally
followed by the name.

It is allowed to define these labels more than once, and it can keep track
of all of their addresses (similar to the anonymous labels found in some
other assemblers).

In an expression, you can use / and the name (if applicable) followed by
? to access the current counter, # to access the total counter, or any
number of + or - to access the label occuring that many spaces forward or
backward from the use.


== Bank chaining ==

If you give a bank the same name as a previous bank, then it will chain
them together; once one 8K bank runs out it will advance to the next bank
and set the page number correctly.

To set a bank name, put a comma and quoted string after the bank number.


== Pseudopages ==

Pseudopage numbers are simply added to the value to write to the map data.
They are set by specifying a number after a CODE or DATA command.

Note: The low two bits and high three bits are used by the assembler; the
other three bits can be used for your own use.


== Filenames from standard input ==

Where a quoted filename is expected, you may use an ampersand to instead
read the filename from standard input.

Note, that it will read it twice; once for each pass. You can avoid this
by using a condition involving ?X in order to do it only once.

by on (#97320)
Get PCEAS2 and and try to incorperate all features to it's program for compatibility, PCEAS2 has lots of essential fixes even for use in 6502 mode!

http://www.pcedev.net/pceas/bin/pceas2_ver322.zip

Credit Tomaitheous for his work if implented

Also, Please incorporate NESASM3 features (derived from NESASM) as well!

http://www.nespowerpak.com/nesasm/

by on (#97322)
Matter of opinion, but: those "NES/Famicom" instructions aren't really instructions per se. They're undocumented opcodes where the behaviour can be established via use of visual6502, I believe.

I would not recommend implementing them as opcodes, because honestly there's no guarantee (in my mind) that they're going to work on every machine or even in every emulator. So basically, these kind of instructions should not be enabled by default; possibly a pseudo-op (ex. .UNDOCOPS) could enable use of them, but by default should not exist (e.g. without the pseudo-op in use, "ARR" would claim to be an unrecognised opcode).

Truly/sincerely I wish people would just stick with what are established, documented, known/proper opcodes and stop trying to implement weird shit.

by on (#97323)
koitsu wrote:
Matter of opinion, but: those "NES/Famicom" instructions aren't really instructions per se. They're undocumented opcodes where the behaviour can be established via use of visual6502, I believe.

I would not recommend implementing them as opcodes, because honestly there's no guarantee (in my mind) that they're going to work on every machine or even in every emulator. So basically, these kind of instructions should not be enabled by default; possibly a pseudo-op (ex. .UNDOCOPS) could enable use of them, but by default should not exist (e.g. without the pseudo-op in use, "ARR" would claim to be an unrecognised opcode).

Truly/sincerely I wish people would just stick with what are established, documented, known/proper opcodes and stop trying to implement weird shit.


Amen.

by on (#97324)
[opinion] They don't have to run in Emu/Clones, they only have to run on the NES.[/opinion]

by on (#97325)
But emulators are consistent, and according to Martin Korth, the illegal instructions do not behave consistently on some 6502-based systems. Lack of consistent behavior seems like a good reason to avoid using them.

by on (#97328)
Some behave consistently, some do not. Stick to the ones that do and you'll be fine. Opcodes like LAX (load A and X with the same value from memory) are perfectly safe (if you look at the bits of the LDA abs/LDX abs opcodes you'll understand why).

by on (#97330)
koitsu wrote:
So basically, these kind of instructions should not be enabled by default; possibly a pseudo-op (ex. .UNDOCOPS) could enable use of them

Like ca65's 6502X mode perhaps?

Quote:
Truly/sincerely I wish people would just stick with what are established, documented, known/proper opcodes

Apart from a few unstable instructions that try to read and write the special bus at the same time (and hence introduce "line noise"), they are all established and documented. Some even appear useful.

by on (#97336)
thefox wrote:
Some behave consistently, some do not. Stick to the ones that do and you'll be fine. Opcodes like LAX (load A and X with the same value from memory) are perfectly safe (if you look at the bits of the LDA abs/LDX abs opcodes you'll understand why).
It is what I have done; looking at the lists of unofficial opcodes, I have not included the ones which do not behave consistently. (And an emulator really should implement all the consistent unofficial opcodes; possibly with an option switch to tell it to emulate them or to display an error message; and to have it log warnings or errors for inconsistent opcodes.)

Quote:
Like ca65's 6502X mode perhaps?
I might be able to do something like that.

I have implemented some PCEAS2 features but have not yet recreated the ZIP. I have not yet looked at NESASM3, but will do so later this week (hopefully).

Quote:
Truly/sincerely I wish people would just stick with what are established, documented, known/proper opcodes and stop trying to implement weird shit.
You need not use the unofficial opcodes if you do not want to do so.

Also, the unofficial HLT opcode is used to stop the emulator which is built-in to my build of MagicKit; I could move it to the main instruction list instead of NES/Famicom specific if it seem useful to do so, even though other target machines may use this instruction opcode for something else.

Other features that I have the idea but I may or may not implement:
  • Additional target machines (other than only NES/Famicom and PC-Engine).
  • Defer labels, which can be targeted from instructions that target memory addresses but the target address may not be known until after the emulator runs to decide the target (and possibly other things based on where it is used and how many times).
  • Character map for string literals in .DB instructions (possibly with a prefix to tell the difference from ASCII strings).
  • Namespaces.
  • SWEET16 instructions (perhaps only if target machines are implemented that are using SWEET16).
  • Include user-defined error messages in .FAIL command.
Re: MagicKit assembler new unofficial version
by on (#97554)
I have now added counted labels (something similar to ca65's unnamed labels, although they can optionally be given names too).

Next I intend to add character mappings and possibly some other things.
Re: MagicKit assembler new unofficial version
by on (#97938)
Some ideas (if you have question/comment please post) (not yet implemented):
  • .NES2SUB: Submapper number
  • .NES2PRGRAM: Amount of PRG-RAM (both battery and non-battery are specified)
  • .NES2CHRRAM: Amount of CHR-RAM (both battery and non-battery are specified)
  • .NES2TV: NTSC/PAL/both
  • .NES2VS: Mode for VS Unisystem
  • .UNIFMAP: Mapper name for UNIF
  • .UNIFTV: TV system (NTSC/PAL/both) for UNIF
  • .UNIFCTRL: Specify which controllers are used (UNIF)
  • .UNIFCHECK: Add checksum information to UNIF files (automatically calculated)
  • .UNIFBATTERY: Enable battery RAM (UNIF)
  • .UNIFVRAM: Enable CHR-RAM even if ROM is present (UNIF)
  • .UNIFMIRROR: Specify mirroring for UNIF
  • .UNIFPRG: Specify address and length of PRG ROMs (UNIF)
  • .UNIFCHR: Specify address and length of CHR ROMs (UNIF)
  • .FAMISYM: Add an entry to DotFami symbol table
  • .FAMIMAP: Specify filename for binary .cart file included as mapper codes in DotFami
  • .FAMILABEL: Automatically add labels to DotFami symbol table
  • .FAMICPU: DotFami CPU mode flag
  • .FAMIEXT: Specify the value of an external parameter for DotFami ($FE and $FF commands in the .cart file are parsed and decided using this)

NES 2.0 is used if any .NES2*** commands are used or if mapper numbers or other numbers are out of range for iNES. UNIF is used if .UNIFMAP command is used. DotFami is used if any .FAMI*** commands are used. Otherwise it uses iNES format.
Re: MagicKit assembler new unofficial version
by on (#97939)
zzo38 wrote:
NES 2.0 is used if any .NES2*** commands are used or if mapper numbers or other numbers are out of range for iNES. UNIF is used if .UNIFMAP command is used. DotFami is used if any .FAMI*** commands are used. Otherwise it uses iNES format.

I'd like to recommend that plain iNES1 headers are never used, since the entire point of NES2.0 is to be backwards compatible.
Re: MagicKit assembler new unofficial version
by on (#97944)
lidnariq wrote:
zzo38 wrote:
NES 2.0 is used if any .NES2*** commands are used or if mapper numbers or other numbers are out of range for iNES. UNIF is used if .UNIFMAP command is used. DotFami is used if any .FAMI*** commands are used. Otherwise it uses iNES format.

I'd like to recommend that plain iNES1 headers are never used, since the entire point of NES2.0 is to be backwards compatible.
Some emulators (maybe other programs too) might expect the unused bits (and bytes) to be zero. Also, since some .NES files might have "DiskDude" starting on one of the bytes which was previously unused, it might treat the entire byte as zero if the unused bits are nonzero, for compatibility with such files. Another thing is that some files using this assembler may not know/care about NES 2.0 so they won't set the amount of PRG-RAM and CHR-RAM. These are a few reasons to not set those bits to activate NES 2.0 unless it is being used. (You can write .NES2SUB 0 if it is necessary to force NES 2.0 to be used without otherwise affecting the header.)
Re: MagicKit assembler new unofficial version
by on (#97971)
But if we're trying to achieve the widespread deploy of NES2.0—and we should be, because it should solve all the ambiguities of the iNES1format—NES2 should, at the very least, be the default.

Nestopia added NES2 support forever ago; Nintendulator detects it; FCEUX completely ignores it (but only explicitly checks for "DiskDude!", "demiforce", and "Ni03" garbage). Because it's backwards compatible, it's ok if the emulator throws away any part except the top 4 bits of the mapper number. Widespread deploy of the standard is the best way to encourage other emulators to adopt it, which will in turn let people know that they can make homebrew that directly targets SOROM or SXROM.
Re: MagicKit assembler new unofficial version
by on (#98486)
I have added the .NES2*** commands and corrected some problems with .MACGOTO command. (I have not yet added character mapping, .UNIF***, and .FAMI***, but eventually I will do so.)
Re: MagicKit assembler new unofficial version
by on (#124379)
It has been upgraded. New features includes:
  • Bank chaining, as a way to fake banks larger than 8K.
  • Additional registers in the postprocessor VM for accessing the ROM data in a way similar to how the PPU does.
  • The error message "Internal error [1]!" has been changed to "Symbol value changed between passes!"
  • A few new MACSET modes have been added.

Support for UNIF and FAMI have been dropped (they were never really supported anyways), although character mapping may be added in a later version.
Re: MagicKit assembler new unofficial version
by on (#124389)
Quote:
You need nkf (Network Kanji Filter) to compile ppmckc properly on un*x system


I'm on a Win64 system, And a version for MinGW(32 or 64) doesn't exist!

Is this a full-on Requirement, or can support for NKF be removed?

EDIT: NKF is os-independent, Misread about it... Should rebuild with MinGW when ready!
Re: MagicKit assembler new unofficial version
by on (#124495)
It has quickly been updated again; here is a list of some new features:
  • Command-line option to override output filename.
  • Some new ?letter expressions.
  • Map file output (contains map of used ROM space and all symbols in the assembler).
  • Pseudopage numbers (usable with map files and postprocessors).
  • Custom character sets.
  • Bank chaining now works with the DS command too.
Re: MagicKit assembler new unofficial version
by on (#127571)
Hi,
I downloaded and compiled your version of nesasm and tried "bank chaining", but it doesn't work. Here's how I try to make it work:
Code:
 .bank 0,"Music"
 .org $8000

;Here goes some code.

 .bank 1,"Music"
 .org $A000

;Empty bank, nothing here.


Code in bank 0 exceeds 8kb and I still get the sam error as in the old nesasm:
Code:
Bank overflow!, offset > $1FFF!


I tried some other combinations with the name of the bank, but none works. How I'm suposed to make it correctly?
Re: MagicKit assembler new unofficial version
by on (#127574)
Denine wrote:
Hi,
I downloaded and compiled your version of nesasm and tried "bank chaining", but it doesn't work. Here's how I try to make it work:
Code:
 .bank 0,"Music"
 .org $8000

;Here goes some code.

 .bank 1,"Music"
 .org $A000

;Empty bank, nothing here.


Code in bank 0 exceeds 8kb and I still get the sam error as in the old nesasm:
Code:
Bank overflow!, offset > $1FFF!


I tried some other combinations with the name of the bank, but none works. How I'm suposed to make it correctly?

The bank has to be named before the overflow occurs, so do it like this:
Code:
 .bank 1,"Music"

 .bank 0,"Music"
 .org $8000

;Here goes some code.
Re: MagicKit assembler new unofficial version
by on (#127575)
Thanks and...sorry to be such a bother, but I have other problem now.
For some reason, your version do not recognize labels when pointers are made(?). Here's what I'm doing:
Code:
 .bank 1,"Music"
 .bank 0,"Music"
 .org $8000

 .dw label

;enough code and data to cross 8kb mark

label:
 ;something


The error I'm getting is "Syntax error in expression".
The whole project assembles correctly with standard nesasm.
Re: MagicKit assembler new unofficial version
by on (#127577)
Denine wrote:
For some reason, your version do not recognize labels when pointers are made(?).
....
The error I'm getting is "Syntax error in expression".
The whole project assembles correctly with standard nesasm.
That's strange...it works on my computer!

What line number is the error? Check which expression is error, maybe that helps a bit.
Re: MagicKit assembler new unofficial version
by on (#127581)
Aaahh..I got it now.
Original NESASM seems to support more letters in one line.
The thing is, I usually sort my pointer by 16 per line, so I can count them more easily.
...so my line was:
Code:
 .dw Label1,Label2,Label3(...)Label16

And NESASM accepted this. (This is probably bad habit of sorting pointers like that, right?) But your version supports less letters per line. So, I just changed my pointer lines to:

Code:
 .dw Label1,Label2,Label3,Label4
 .dw Label5,Label6,Label7,Label8
 (etc)


Next, I'v got yet another error. I'm using shiru's Famitone 2.
The music file converted by text2data tool have line:
Quote:
.dw .samples-4

I just deleted "-4" and finally, compiled the ROM. I just though it may be worth mentioning

But now, the ROM is not working! The part of insides of my Main file:
Code:
 .bank 1,"name"
 .bank 0,"name"
 .org $8000
 .include "Music\Famiton2.asm" ;Music driver

Music.TBL:
 .dw Music

 .include "GFX/GFX_Load.txt" ;GFX

 .include "SYS/Scoring.txt" ;Score calculations
 .include "GFX/Palety.txt" ;Palette works
 .include "SYS/Buffer.PPU.txt" ;PPU Buffer code
 .include "SYS/KEYPAD.txt" ;Keypad handler
 .include "SYS/Grafika.txt" ;Various, turning on and off ppu, waiting for Vblank.

Reset code is at $F000, it clears RAM, then waits for Vblank few frames.

I traced the code with FCEUX and it seems that game crashes because jsr points to...somewhere in GFX data. jsr was supposed to point at waitVblank function but it does not. Using Hex editor(the one built in FCEUX), I found the waitVblank code at $B502, but jsr points at $9544...
The GFX_Load have several graphics files included, they cross Bank0 and Bank1 boundary.
Sorry, to be such a pain...it's probably my mistake somewhere...I can send you a source files via PM, if you want.
Re: MagicKit assembler new unofficial version
by on (#150811)
While I have posted a new version a few months ago I forgot to update this forum thread. Here is a partial list of changes:
  • A few new ports for use by the postprocessor/custom-output-routine (now it is possible to compile code while the postprocessor is running, if you are careful!)
  • Some new MACSET subcommands
  • A few bugs with writing NES 2.0 headers have been fixed
  • Some other bug fixes (I forget the details now)

I don't know whether or not this fixes Denine's problem. It may be a bug in my program, in Famitone 2, or in your program somehow. If there are any real bug reports with sufficient details, please report them here. (I myself have not had any problems with the current version.)

Note that it is possible to do "compile time debugging" using macros, such as the following:
Code:
   macro compile_time_debug
   if ?X
   macset 1,4,\1
   fail \1
   endif
   endm
If you want the output in hexadecimal, please replace macset 1,4,\1 wth org \1 (in which case the fail message will be the expression and the address printed to the left is the value; with the MACSET it will print the current address to the left and the value in decimal format on the right).