MagicKit assembler new unofficial version

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

MagicKit assembler new unofficial version

Post by zzo38 »

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: Select all

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.
Last edited by zzo38 on Fri Jul 10, 2015 9:36 pm, edited 6 times in total.
User avatar
Hamtaro126
Posts: 818
Joined: Thu Jan 19, 2006 5:08 pm

Post by Hamtaro126 »

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/
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

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.
User avatar
Hamtaro126
Posts: 818
Joined: Thu Jan 19, 2006 5:08 pm

Post by Hamtaro126 »

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.
AKA SmilyMZX/AtariHacker.
3gengames
Formerly 65024U
Posts: 2284
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

[opinion] They don't have to run in Emu/Clones, they only have to run on the NES.[/opinion]
User avatar
Dwedit
Posts: 4922
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

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.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Post by thefox »

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).
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

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?
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.
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Post by zzo38 »

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.)
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).
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.
(Free Hero Mesh - FOSS puzzle game engine)
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Re: MagicKit assembler new unofficial version

Post by zzo38 »

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.
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Re: MagicKit assembler new unofficial version

Post by zzo38 »

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.
Last edited by zzo38 on Tue Sep 18, 2012 11:58 pm, edited 1 time in total.
(Free Hero Mesh - FOSS puzzle game engine)
lidnariq
Posts: 11430
Joined: Sun Apr 13, 2008 11:12 am

Re: MagicKit assembler new unofficial version

Post by lidnariq »

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.
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Re: MagicKit assembler new unofficial version

Post by zzo38 »

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.)
Last edited by zzo38 on Sat Aug 11, 2012 11:52 pm, edited 1 time in total.
(Free Hero Mesh - FOSS puzzle game engine)
lidnariq
Posts: 11430
Joined: Sun Apr 13, 2008 11:12 am

Re: MagicKit assembler new unofficial version

Post by lidnariq »

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.
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Re: MagicKit assembler new unofficial version

Post by zzo38 »

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.)
(Free Hero Mesh - FOSS puzzle game engine)
Post Reply