It is currently Fri Jul 19, 2019 9:35 am

All times are UTC - 7 hours



Forum rules





Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sat May 25, 2019 12:07 am 
Offline

Joined: Sat Oct 06, 2018 10:15 am
Posts: 20
Since I no longer had the original X816 assembler source code I began rebuilding a new 65816 assembler a few months ago using Free Pascal but I've gotten to the point where it needs some real world testing and suggestions. The archive contains only the executable and a readme which is the actual directive/opcode table embedded into the .exe. It's a brief rundown of all the current and some future planned directives and functions. Scroll further down the readme and you will see the opcode tables for 65816, 6502, SPC700 (both native and 65816-style), as well as a partial SuperFX implementation.

Here's a short example of the setup, with a couple of nested repeats and a final bin save.
Code:
.snes lorom
.list
.symbol
.verbose off
.repeat 3,@y
.repeat 10,@x
nop
.echox "current address:",@pc
.echox @x+@y*10
.endrepeat
.endrepeat
.snes savebin

How functionable is it? I've been able to convert some older simple source codes, including the Tricks Zoomer which I recoded into mode 21 and use some direct page addressing just for testing. Really only the 65816 side has been regularly tested. I cut/pasted some SPC700 instructions with deliberate errors to test but that's about it.
Code:
   36 00008042                                               .cpu      spc700                 
.target cpu SPC700
   37 00000000                                               .base     $0000                   
   38 00000000 39                                            and       (x),(y)                 ;$39,1,0,
   39 00000001 28 34                                         and       a,#$1234                ;$28,2,4,
*** error #2 line 39 value out of range >255
   40 00000003 26                                            and       a,(x)                   ;$26,1,0,
   41 00000004 37 34                                         and       a,[$1234]+y             ;$37,2,1,
*** error #3 line 41 address out of range >255
   42 00000006 27 35                                         and       a,[$1234+1+x]           ;$27,2,1,
*** error #4 line 42 address out of range >255
   43 00000008 24 12                                         and       a,$12                   ;$24,2,1,
   44 0000000A 34 12                                         and       a,$12+x                 ;$34,2,1,
   45 0000000C 25 34 12                                      and       a,$1234                 ;$25,3,2,
   46 0000000F 35 35 12                                      and       a,$1234+1+x             ;$35,3,2,
   47 00000012 36 35 12                                      and       a,$1234+1+y             ;$36,3,2,
   48 00000015 38 34 34                                      and       $1234,#$1234            ;$38,3,33,
*** error #5 line 48 value out of range >255
   49 00000018 29 34 34                                      and       $1234,$1234             ;$29,3,32,
*** error #6 line 49 address out of range >255
   50 0000001B 6A 34 32                                      and1      c,/$1234.1              ;$6a,3,42,
   51 0000001E 4A 34 52                                      and1      c,$1234.2               ;$4a,3,42,
   52 00000021 88 21                                         adc       a,#$4321               
*** error #7 line 52 value out of range >255
   53 00000023 97 70                                         adc       a,[main&$ff]+y         
   54 00000025 0A 34 72                                      or1       c,$1234.3               
   55 00000028 3B 12                                         rol       $12+x                   
   56 0000002A 75 59 01                                      cmp       a,345+x                 
   57 0000002D 6F                                            ret                               
   58 00008042 [00002E]                                      .endb                             
   59 00008070                                                                                 
   60 00008070                                               .cpu      65816                   
.target cpu 65816
   61 00008070                             main:                                               
   62 00008070 4C 70 80                    -                 jmp       -                       


Attachments:
ymas00181e.7z [123.45 KiB]
Downloaded 100 times


Last edited by noyen1973 on Fri May 31, 2019 2:08 am, edited 1 time in total.
Top
 Profile  
 
PostPosted: Sat May 25, 2019 1:02 pm 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3697
Location: Indianapolis
I tried it on my old x816 project, only changing ".hirom on" to ".snes hirom". It makes it up until it hits an .incbin, then does this:
Code:
An unhandled exception occurred at $0040EAD3:
EInOutError: Access denied
  $0040EAD3
  $0040A8F6
  $0041A2CA
  $0041B3B3
  $0041B793

If I comment it out, it goes further until it hits the next .incbin. The included files do exist in the same directory (and the source .include directive worked fine).


Top
 Profile  
 
PostPosted: Sat May 25, 2019 9:05 pm 
Offline

Joined: Sat Oct 06, 2018 10:15 am
Posts: 20
Check the file attributes for your bin files, they might be set as read-only. I don't know why that should matter in Free Pascal as the file is only opened for reading and not writing. I've fixed the problem in my current version.


Top
 Profile  
 
PostPosted: Sun May 26, 2019 4:39 pm 
Offline
User avatar

Joined: Thu Jan 19, 2006 5:08 pm
Posts: 760
I would like a way for using text with ASCII to use SNES's properties/attributes with it (i.e. .TW, also known as TEXTWORD), In other words, two ways to implement this is to:

1: add .StrAt(String) like in CA65, as I have a "TW" macro that uses that.

2: Look at the implementation for ASM16's version of TW, search for "ASM16" on GITHUB (NicklausW maintained it, but no longer updates it as far as I know.)

_________________
AKA SmilyMZX/AtariHacker.


Top
 Profile  
 
PostPosted: Mon May 27, 2019 9:35 am 
Offline

Joined: Sat Oct 06, 2018 10:15 am
Posts: 20
Are you referring to string handling functions like these?

Code:
$2000,%11,$21,.strlen      ; .strlen(string)
$2100,%11,$22,.leftstr      ; .leftstr(string,index)
$2100,%11,$22,.left         ; same as .leftstr
$2200,%11,$22,.rightstr      ; .rightstr(string,index)
$2200,%11,$22,.right      ; same as .rightstr
$2300,%11,$22,.midstr      ; .midstr(string,index,length) -no length is to end=255
$2300,%11,$22,.mid         ; same as .midstr
$2300,%11,$22,.copy         ; same as .midstr
$2400,%11,$22,.delstr      ; .delete(string,index,length) -no length is to end=255
$2400,%11,$22,.delete      ; same as .delstr
$2500,%11,$21,.instr      ; .instr(substring,string)
$2500,%11,$21,.pos         ; .same as .instr
$2600,%11,$22,.trim         ; .trim(string)
$3000,%11,$12,.inttostr      ; .intostr(expr)
$3100,%11,$21,.strtoint      ; .strtoint(string)
$3200,%11,$12,.inttohex      ; .inttohex(expr)
$3300,%11,$21,.hextoint      ; .hextoint(string)

That's a cut from the current version which has them all implemented. The version I put up had some of them commented out as they were on my todo list. I just tested them in a macro and it works. Prior to your message I had only tested them using .echox directive. Here's a sample of the string functions in a macro. I believe the function you are looking for is .instr(<substring>,<string>) which returns the position.
Here's the macro definition:
Code:
.macro cowboy greeting
   .echox @nargs
         nop
        .if "@1"="Howdy"
        .echo "greeting"
        .else
        .echo "I'm not a cowboy."
        .endif
        .if .instr("y","@1")=5
        .echox "'y' is the ",.instr("y","@1"),"th character"
        .endif
.endm

Here's the assembly listing:
Code:
   25v00008000                                               .verbose  off                     
   26M00008000                                               cowboy    Howdy                   
.macro cowboy greeting(1)=Howdy(1)
   27 00008000                                               .echox    @nargs                 
             1
   28 00008000 EA                                            nop                               
   29T00008001                                               .if       "Howdy"="Howdy"         
   30 00008001                                               .echo     "Howdy"                 
             Howdy
   31 00008001                                               .else                             
   33 00008001                                               .endif                           
   34T00008001                                               .if       .instr("y","Howdy")=5   
   35 00008001                                               .echox    "'y' is the ",.instr("y","Howdy"),"th character"
             'y' is the 5th character
   36 00008001                                               .endif                           
   37M00008001                                               cowboy    Hello                   
.macro cowboy greeting(1)=Hello(1)
   38 00008001                                               .echox    @nargs                 
             1
   39 00008001 EA                                            nop                               
   40F00008002                                               .if       "Hello"="Howdy"         
   42 00008002                                               .else                             
   43 00008002                                               .echo     "I'm not a cowboy."     
             I'm not a cowboy.
   44 00008002                                               .endif                           
   45F00008002                                               .if       .instr("y","Hello")=5   
   47 00008002                                               .endif                           
   48V00008002                                               .verbose  on                     
.verbose reporting on

Hamtaro126 wrote:
I would like a way for using text with ASCII to use SNES's properties/attributes with it (i.e. .TW, also known as TEXTWORD), In other words, two ways to implement this is to:

1: add .StrAt(String) like in CA65, as I have a "TW" macro that uses that.

2: Look at the implementation for ASM16's version of TW, search for "ASM16" on GITHUB (NicklausW maintained it, but no longer updates it as far as I know.)


Top
 Profile  
 
PostPosted: Mon May 27, 2019 12:35 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4154
Location: A world gone mad
I can't figure out what Hamtaro is actually asking for. Another case where being terse is not helpful... :\

asm16 is a fork of asm6/asm6f (6502 assembler) but intended for 65816. It comes with no documentation, no syntax details, no examples (the stuff in test/ does not actually use TW). which to me immediately says "throw this out and do not use it ever". I had to refer to commits and source code to figure out what this TW directive actually did:

https://github.com/nicklausw/asm16/comm ... 82355f4df0

Without any examples, and with virtually no source code comments, I can't figure out the exact syntax or behaviour of this psuedo-op. It looks like it might be something like .TW $1234,"some string" but I don't know for sure. The changelog and top-of-function comment says that it parses a string a byte at a time and emits a word/16-bit unsigned value based upon character | $1234 (using my example) for each byte. E.g. .TW $1234,"Hello" would emit five (5) 16-bit words total, of $48 | $1234 (H), $65 | $1234 (e), etc... ? Is this actually what it does?

As for ca65's .strat(), that looks to be completely different. That, to me, looks like a way to get the raw byte/value from a string (or any part of a generated label/ROM) based upon an index/offset, starting at 0. In other words:

Code:
input: .byte "Hello World"

.strat(input, 0) == would return "H"
.strat(input, 1) == would return "e"
.strat(input, 2) == would return "l"
.strat(input, 10) == would return "d"

To me this looks like .midstr in YMAS, with a length of 1.

You could therefore simulate TW by using a macro with .repeat and .strlen(), though I dunno if .midstr and the like start at 0 or 1 for offsets (I suspect 1 given that YMAS is in FreePascal).


Top
 Profile  
 
PostPosted: Wed May 29, 2019 7:44 pm 
Offline
User avatar

Joined: Sat Jan 03, 2015 5:58 pm
Posts: 371
Location: ...
koitsu wrote:
asm16 is a fork of asm6/asm6f (6502 assembler) but intended for 65816. It comes with no documentation, no syntax details, no examples (the stuff in test/ does not actually use TW). which to me immediately says "throw this out and do not use it ever".

Good thinking, as much as I hate to say it. asm16 was just another "I'm never satisfied with existing assemblers" project that even once it was working, I didn't actually care for that much; took more to byuu's bass, which I've stuck with. Also the test program...just...no. Golden example of throwing code around without knowing what it does.

The TW directive takes one word and one string, and each character of the string is OR'd with the word to output two new bytes.
Code:
.TW $FF00,"HIYA"

HIYA is 48 49 59 41, so the output is FF 48 FF 49 FF 59 FF 41.

It's freaky, I know, but asm6 has always allowed some arithmetic on strings ("HIYA"-1 outputs 47 48 58 40) so this didn't seem too far out there. Hopefully a better solution can be found in some other assembler (most likely ca65) so my one loyal asm16 user can move on to better, much more well-maintained things.


Top
 Profile  
 
PostPosted: Fri May 31, 2019 5:21 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4154
Location: A world gone mad
Re: .incbin-related "Access denied" error: I wonder if this relates to incbin'd file size (or file offset, ex. reading past EOF), referencing the same file multiple times and stomping over a filehandle (?), or bank padding somehow. Windows' "access denied" error is not always about file permissions.


Top
 Profile  
 
PostPosted: Sat Jun 01, 2019 2:20 am 
Offline

Joined: Sat Oct 06, 2018 10:15 am
Posts: 20
koitsu wrote:
Re: .incbin-related "Access denied" error: I wonder if this relates to incbin'd file size (or file offset, ex. reading past EOF), referencing the same file multiple times and stomping over a filehandle (?), or bank padding somehow. Windows' "access denied" error is not always about file permissions.

The archive has been updated to version 0.0181e which has a rewrite of .incbin to use a filestream rather than directly opening a file. I couldn't recreate the access denied error with the changes but that may not be the same for others... Needs testing.

More of the string functions have also been implemented. However I have noticed the parser doesn't do well when combining multiple functions. The opcode matching was also adjusted because extra spaces in the operand field confused the decoding of addressing modes and still does. For example LDA ($32,X ) doesn't get recognized because of the extra space between the 'X' and ')'. This was apparent after trying to assemble the spc700 ipl rom from SPCTECH by mukunda.

At the moment I'm cleaning up the source code and trying to improve the internals. Catching up on 20+ years of assembler evolution is not easy.


Top
 Profile  
 
PostPosted: Mon Jun 03, 2019 10:05 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 1177
Location: Hokkaido, Japan
Could I ask for a bit of background to this? This is a new version of this? It seems to be modelled of the C64/128's native assembler.
The current state of the readme file does not explain much else but different directives, but I see that there are SNES-specific directives. Is this assembler able to do general 65816 stuff as well, or is it SNES only? I guess the 6502 must be generic at least.

I've been hoping for a good 65816 and SPC700 assembler that works on modern computers, and this looks promising.


BTW asm16 isn't that bad since it can do everything asm6 can do. It has a few new (undocumented) features, but it was never completed. I don't think the direct page directives was ever added.
I personally can't stand the non-standard syntax in bass, and stopped using it. I rather use ca65 or even asm16.


Top
 Profile  
 
PostPosted: Tue Jun 04, 2019 4:50 pm 
Offline

Joined: Sat Oct 06, 2018 10:15 am
Posts: 20
Pokun wrote:
Could I ask for a bit of background to this? This is a new version of this? It seems to be modelled of the C64/128's native assembler.
The current state of the readme file does not explain much else but different directives, but I see that there are SNES-specific directives. Is this assembler able to do general 65816 stuff as well, or is it SNES only? I guess the 6502 must be generic at least.

I've been hoping for a good 65816 and SPC700 assembler that works on modern computers, and this looks promising.


BTW asm16 isn't that bad since it can do everything asm6 can do. It has a few new (undocumented) features, but it was never completed. I don't think the direct page directives was ever added.
I personally can't stand the non-standard syntax in bass, and stopped using it. I rather use ca65 or even asm16.

I wrote X816 with the help of koitsu over 20 years ago and have recently rediscovered the SNES homebrew scene. X816 does not run under the modern Windows environment without using DOSBOX, so I thought I'd try writing a new assembler based on it. Unlike my older assembler attempts by the name of Snesasm and Tricksasm which I shared publicly, the X816 source code was never shared and is long lost. YMAS is my attempt at rewriting a SNES assembler and more. The core of the assembler works much like Table Assembler so without too much hard coding I can add in instruction sets for other CPUs. YMAS is far from being complete and remains largely untested aside from the 65816 end of things but I am actively working on it in.

Some other assemblers you might want to consider are ASAR or WLA-DX.


Top
 Profile  
 
PostPosted: Wed Jun 05, 2019 1:57 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 1177
Location: Hokkaido, Japan
I see, thanks for the explanation.

I meant to ask if it forces things like headers and ROM size for you or if you have control of it yourself. So that it could be used for non-SNES 65816 devices as well for example I mean.


Top
 Profile  
 
PostPosted: Wed Jun 05, 2019 3:50 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 4154
Location: A world gone mad
It depends on the platform.

NES/NES 2.0 header support is planned but as usual, a complicated mess. For now you're better off just making the 16-byte header yourself through .db directives or the classic copy /b header.bin+build.bin > build.nes model.

SNES cartridge header support -- the "old style" header -- is provided through .snes. Please refer to the documentation as such:

Code:
$0080,0,$00,.snes @*
;.snes <function>
;Once the .snes directive is used the assembler will assign the target
;platform to Super NES and list the header information.  Changing the
;MODE/TYPE in the header will also change the MAPMODE and ROMSPEED and
;vice versa as they are both part of MODE/TYPE.  Using lorom, hirom,
;slowrom or fastrom will change the proper header information and set
;the start address to either $008000, $808000 or $c00000 to match the
;mode.  This is best done at the beginning of your source code.  If your
;source code only represents a fragment to be injected into another file
;it is not necessary to use those .snes directives as their primary use
;is for a large project.
;
;   lorom    Sets header info for mode 20, default "slow", see below.
;     "lorom slow", mode 20 32kB, romspeed=slow, org $008000
;     "lorom fast", mode 20 32kB, romspeed=fast, org $808000
;   hirom    Sets header info for mode 21 64kB, romspeed=fast, org $c00000
;   savebin  Saves a binary file based on map mode and rom speed, or the
;            lowest and highest address.
;   list     Lists the cartridge header details

; ($ffc0)   TITLE=<21 bytes>
; ($ffd5)   MODE=<byte> same as ROMSPEED/MAPMODE
; ($ffd5)   TYPE=<byte> same as ROMSPEED/MAPMODE
; ($ffd5.4)   ROMSPEED=<slow/fast>
; ($ffd5.0-3)MAPMODE=<value 0-15>
; ($ffd6)   CHIPSET=<byte>
; ($ffd7)   ROMSIZE=<byte>
; ($ffd8)   RAMSIZE=<byte>
; ($ffd9)   COUNTRY=<byte>
; ($ffda)   DEVELOPER=<byte>
; ($ffdb)   VERSION=<byte>
; ($ffdc/d)   CHECKSUMX=<word or CALC/AUTO/-1>
; ($ffde/f)   CHECKSUM=<word or CALC/AUTO/-1>
; SNES header information taken from "Fullsnes - Nocash SNES Specs".
; *** Does not calculate the checksum/checksumx yet

Real world example:
Code:
;
; Start of file
;
    .cpu 65816

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Cartridge header ($FFC0-FFDF)                                           ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    .snes lorom           ; Mode 20
    .snes slowrom         ; 2.68MHz
    .snes title="(C) 1993 Norman Yen"
    .snes chipset=$00     ; ROM only
    .snes romsize=$08     ; 1-2mbit
    .snes ramsize=$00     ; No SRAM
    .snes country=$01     ; North America
    .snes developer=$FF   ; Undefined
    .snes version=$00
    .snes checksumx=AUTO
    .snes checksum=AUTO

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Vectors ($FFE4-FFFF)                                                    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; All your .irq statements go here
;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; General equates                                                         ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; All your equates, variables, etc. go here
;



    .org $008000   ; Or whatever address

;
; ... all your code, data, etc. goes here
;


;
; Save resulting ROM; this must be put at the end of the file!
;
    .snes savebin "build.sfc"   ; Save resulting ROM

Since checksum/complement generation isn't implemented yet, you can use ucon64 to generate them for you. I use this in my build script: ucon64.exe -q --nbak --snes --chk build.sfc

If you want the "new style" SNES cartridge header, you can add it yourself manually via .db/.dw statements at the appropriate offset using .org/.pad etc... You should probably not try to use both methods together (i.e. .snes combined with .db/.dw for $FFB0-FFBF) but do whatever you wish. It's a classic assembler: it does what you tell it.


Top
 Profile  
 
PostPosted: Thu Jun 06, 2019 7:32 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 1177
Location: Hokkaido, Japan
So I can do everything manually if I want with statements like db, org and pad. That's actually what I prefer. Checksum/complement calculation would be nice though, I'm currently also using ucon64 in my build script.

Quote:
It's a classic assembler: it does what you tell it.
That's what I wanted to hear. :)


Top
 Profile  
 
PostPosted: Sat Jun 08, 2019 10:59 pm 
Offline

Joined: Sat Oct 06, 2018 10:15 am
Posts: 20
Here's an update, v0.0181f.

Improved SPC700 assembly
- Tested with Asar's "arch-spc700.asm"
- Use .cpu spc700

Improved SuperFX assembly
- Tested with Asar's "arch-superfx.asm" or atleast a version of it as I've found different versions
- Use .cpu superfx

Implemented Checksum and ChecksumX autocalculation
- It's on by default with the first use of a .snes directive otherwise use both .snes checksumx=calc and .snes checksum=calc, and follow up with .snes savebin at the end of your source code

Fixed .byte "text"
- The length of string byte was mistakingly encoded into the bin


Attachments:
ymas00181f.7z [112.48 KiB]
Downloaded 42 times
Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group