The logic is this: if an argument is only one token long (eg "x", "value" or "macro") it is implicitly treated as a "value" argument. If the argument is two tokens long ("value x", "macro value", "macro macro") then the name is the second token and the type is the first token (and can either be "value" or "macro").King Harold wrote:What would happen if you tried to name something "macro"?
Brass 3 (Under Development)
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
I've added a number of bits and pieces; list file exporter plugins, number encoders, data structures and indexing.
For the second half of that statement, here's a real example:
Labels now have types associated with them, which gives them a size and so means that you can use an index (inside []) to access element addresses individually.
You can define new structures at runtime with .struct:
(I've also added a .var directive).
For the second half of that statement, here's a real example:
Code: Select all
ComplexNumber: .data ticomplex -234.5, +0.25 ; -234.5+0.25i
/*
This outputs the data:
8C 82 23 45 00 00 00 00 00
0C 7F 25 00 00 00 00 00 00
To copy the components to OP1 and OP2 you could
do something like this:
ld hl,ComplexNumber[1]
rst rMov9ToOP1
bcall(_OP1toOP2)
ld hl,ComplexNumber[0]
rst rMov9ToOP1
*/
You can define new structures at runtime with .struct:
Code: Select all
.struct Vector3
byte X,
byte Y,
byte Z
.struct Plane
Vector3 Normal,
byte Offset
.struct Edge
Vector3[2] Ends
.varloc 0, 1024
.var Edge SomeEdge
ld (SomeEdge[0].X),a
.var Plane SomePlane
ld a,(SomePlane.Normal.X)
This is so totally insane... I love it!
This is some seriously extreme preprocessing for a z80 assembler I just know people are going to write the most horrific things with this, as well as the most brilliant (and unreadable) things.
Is this really necessary? Can't it "detect" what it is you want? Because usually you'll want the macro style replace with something textual (label, string) and the value with something numeric or a known variable.if an argument is only one token long (eg "x", "value" or "macro") it is implicitly treated as a "value" argument. If the argument is two tokens long ("value x", "macro value", "macro macro") then the name is the second token and the type is the first token (and can either be "value" or "macro").
This is some seriously extreme preprocessing for a z80 assembler I just know people are going to write the most horrific things with this, as well as the most brilliant (and unreadable) things.
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
I don't really like attempting to guess what the user wants. Take the factorial example;Timendus wrote:Is this really necessary? Can't it "detect" what it is you want? Because usually you'll want the macro style replace with something textual (label, string) and the value with something numeric or a known variable.
Code: Select all
#function f(n)
.if n == 0
f = 1
.else
f = n * f(n - 1)
.endif
#endfunction
val = 10
.echoln f(val)
I agree that if you pass a string constant ("") it should default to passing-by-macro, so good idea.
I'm trying to make it as flexible as possible before a release so that people can write useful extra directives and functions for the assembler. The examples are designed to be very silly and over the top to stress-test the parser and preprocessor.This is some seriously extreme preprocessing for a z80 assembler
Edit: I should also mention that thus far I haven't implemented the old Brass-style macros (eg .define ld_a({0}) xor a). I don't know how useful they would be, maybe something for the "legacy" plugin collection I'm arranging (see also: .equ).
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Hm, next "problem" I need some community guidance on.
The output as generated by the compiler is a large array of OutputData structure, which contains the page number, program counter and array of bytes output at that address (array of bytes thanks to output modifiers - unsquished programs have two bytes of output data per byte written by the compiler).
Now, currently, I sort by page then by program counter then write sequentially, which is clearly "wrong" (think of .relocated blocks).
My current idea is to maintain two variables - program counter and "output counter". The output counter increments with the program counter and is set by directives like .org, but if you write to the $ directly ($ = xyz) or use a directive like .relocate only $ gets modified. This way when sorted things end up (hopefully) in the right order.
Any thoughts?
Bear in mind that "holes" in the source code (ie, non-consecutive output addresses) can be present; in a raw file they'd be ignored, in a hex file each data record has an address anyway (so that's OK). Maybe I need a "padded raw" output writer that pads the data so it sits neatly on pages, and have a page definition directive?
I fixed the parser so indexers and field accessors work properly, so "ld a,(Var[2].Plane[3].Normal.X)" now compiles if you wanted something like that. I also fixed right-associative operators (order of precence is from right-to-left, rather than left-to-right, like x = y = 1).
The output as generated by the compiler is a large array of OutputData structure, which contains the page number, program counter and array of bytes output at that address (array of bytes thanks to output modifiers - unsquished programs have two bytes of output data per byte written by the compiler).
Now, currently, I sort by page then by program counter then write sequentially, which is clearly "wrong" (think of .relocated blocks).
My current idea is to maintain two variables - program counter and "output counter". The output counter increments with the program counter and is set by directives like .org, but if you write to the $ directly ($ = xyz) or use a directive like .relocate only $ gets modified. This way when sorted things end up (hopefully) in the right order.
Any thoughts?
Bear in mind that "holes" in the source code (ie, non-consecutive output addresses) can be present; in a raw file they'd be ignored, in a hex file each data record has an address anyway (so that's OK). Maybe I need a "padded raw" output writer that pads the data so it sits neatly on pages, and have a page definition directive?
I fixed the parser so indexers and field accessors work properly, so "ld a,(Var[2].Plane[3].Normal.X)" now compiles if you wanted something like that. I also fixed right-associative operators (order of precence is from right-to-left, rather than left-to-right, like x = y = 1).
Sounds like it should work, but I'm not really up to speed with all that... So don't take my advice
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Well, it "seems" to work. I created a rawpages plugin that outputs the defined pages in their index order, writing X bytes per page where X is the defined size of the page.
As an example, Sega recommend the following SMS memory map for megabit cartridges. There are three "windows" that can be swapped in of 16KB each; they recommend that you use a fixed 32KB in the lower two windows and vary the third window's 16KB page (the final 16KB memory is mapped to RAM).
So, in Brass code;
(KB is a silly function that returns 1024xvalue).
I'm making some parts of the core plugin collection extendable; for example, the SMS requires certain data to be written into the ROM (checksum, TMR SEGA header and so on) as well as SDSC tags (author, description and so on). Thus, a "smsrom" plugin writes the stuff then can hijack the "rawpages" plugin to perform the actual writing to disk.
As an example, Sega recommend the following SMS memory map for megabit cartridges. There are three "windows" that can be swapped in of 16KB each; they recommend that you use a fixed 32KB in the lower two windows and vary the third window's 16KB page (the final 16KB memory is mapped to RAM).
So, in Brass code;
Code: Select all
.defpage 0, $0000, kb(32)
; Page numbers are offset by one so that I can take the page
; of a label (:label) and output that to $FFFF directly to switch
; to the correct page.
.for p is 1 to 6
.defpage p + 1, $8000, kb(16)
.loop
.page 0 ; Implicitly sets $ and output counter = 0
xor a
ld ($FFFC),a ; RAM control.
ld ($FFFD),a ; Page 0 = 0
inc a
ld ($FFFE),a ; Page 1 = 1
inc a
ld ($FFFF),a ; Page 2 = 2
.page 2 ; Implicitly sets $ and output counter = $8000
; ...
I'm making some parts of the core plugin collection extendable; for example, the SMS requires certain data to be written into the ROM (checksum, TMR SEGA header and so on) as well as SDSC tags (author, description and so on). Thus, a "smsrom" plugin writes the stuff then can hijack the "rawpages" plugin to perform the actual writing to disk.
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
The help viewer can now export all of the documentation into a single website (including a contents frame). I'll make it zip up the output files so that it can be easily distributed/downloaded.
I've uploaded a copy here if you want to observe some of the documentation as it grows.
Brass 3 Plugin Documentation
I've uploaded a copy here if you want to observe some of the documentation as it grows.
Brass 3 Plugin Documentation
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
I wrote some output writer plugins for TI development; ti8x, ti83, ti82, ti85, ti86, ti73.
To take advantage of the better page support, each page is output as a different program variable.
I have also promoted ":" to an operator in its own right (eg :y is seen as ":" and "y" rather than ":y") which makes macro replacement much easier.
To take advantage of the better page support, each page is output as a different program variable.
Code: Select all
/* The following would create a group file
containing two programs, PRGMA and PRGMB. */
.page 1
.tivariablename "PRGMA"
.org $9D93
ret
.page 2
.tivariablename "PRGMB"
.org $9D93
ret
/* Naturally, you need to be using a TI program
output writing plugin for this to work. */
To be entirely honest, I understand only about half the things you say, but what I understand of it sounds great
I think I'm going to steal parts of it from you
Why does that look so much better than my documentation?benryves wrote:Brass 3 Plugin Documentation
I think I'm going to steal parts of it from you
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
- driesguldolf
- Extreme Poster
- Posts: 395
- Joined: Thu 17 May, 2007 4:49 pm
- Location: $4080
- Contact:
Don't forget to release a "Hello World!" program!
(I never got the 'old' brass to properly compile a asm program, I kept using devpac8x for doing .bin->.8xp)
anyway, wouldn't it it better to make an .endpage directive?
What happens when u use .page n when you haven't yet defined that page?
And just to be sure, what output does this generate:
EDIT:
is this valid?
(I never got the 'old' brass to properly compile a asm program, I kept using devpac8x for doing .bin->.8xp)
anyway, wouldn't it it better to make an .endpage directive?
that's a good ideabenryves wrote:I have also promoted ":" to an operator in its own right (eg :y is seen as ":" and "y" rather than ":y") which makes macro replacement much easier.
What happens when u use .page n when you haven't yet defined that page?
And just to be sure, what output does this generate:
Code: Select all
x=20
.for t is 0 to x
.db t
x=x-1
t=t*2
.loop
is this valid?
Code: Select all
.module x
y=255
.endmodule
.module x
z=y
.endmodule
;Now should x.y=x.z=255
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Hm, putting .binarymode TI8X \ .variablename "PRGMNAME" should be enough to turn a .bin->.8xp.driesguldolf wrote:Don't forget to release a "Hello World!" program!
(I never got the 'old' brass to properly compile a asm program, I kept using devpac8x for doing .bin->.8xp)
I'm not sure what advantage that would have..?anyway, wouldn't it it better to make an .endpage directive?
The page number will be set (:$ = <page>) and the output and program counters will be set to zero.What happens when u use .page n when you haven't yet defined that page?
As for what will be output, it depends on the output writer. The raw writer will just spit out a binary of all pages, Intel HEX will also emit a correct object file, but the rawpages directive requires that all pages be defined so it knows how to format each page. In the case of undefined pages it displays a warning that it found data on page X, but page X wasn't defined so it doesn't appear in the output.
0, 1, 3, 7, 15.And just to be sure, what output does this generate:Code: Select all
x=20 .for t is 0 to x .db t x=x-1 t=t*2 .loop
Yes. The logic is that the current module name is appended to all newly created labels (so, on the line y=255 it sees "y, hmm, don't know what that is, so I'll create a new label called "x.y").EDIT:
is this valid?Code: Select all
.module x y=255 ; <- .endmodule .module x z=y .endmodule ;Now should x.y=x.z=255
As for label resolution, the compiler starts by searching the current module for a match; if none is found it moves up a module and searches again, moving up until it reaches the "global" label scope.
Probably because I got the MSDN team to design it for me. (Sorry about the awful CSS/HTML, it was chucked together quickly).Timendus wrote:Why does that look so much better than my documentation?
I think I'm going to steal parts of it from you
---
The silly parser in Brass 1 would strip out all whitespace first of arguments (unless it was detected inside a string) and work on that.
A side-effect of that was that the following source would assemble:
Code: Select all
ld h l, 1 23 ; Assembles as ld hl,123
Code: Select all
.deflong some_function(regh, regl)
inc regh regl
.enddeflong
some_function(h,l)
I'm trying to avoid writing parser hacks. Another parser hack in Brass 1 was the replacement of [%var%] with the environment variable "var". As a compatibility hack I wrote a plugin that registers a bunch of macros to replace "[%var%]" with the contents of var (as [%var%] is five tokens - [, %, var, %, and ] - I can only replace the single token "[%var%]") but this doesn't help in the situations where you need to pass in a numeric value. To get around this I cobbled together an eval() function that evaluates whatever is in the argument and returns a numeric value. Thus;
Code: Select all
; Brass 1 code:
.db "[%project_name%]" ; debug_name is a string.
DebugLevel = [%debug_level%] ; debug_level is a number.
; Brass 3 code:
.db "[%project_name%]" ; no change required :)
DebugLevel = eval("[%debug_level%]") ; evaluate to convert string->number.
Code: Select all
.function some_function(regh, regl)
eval("inc " + regh + regl)
.endfunction
some_function("h", "l")
Code: Select all
x = "1"
y = x ; y = string "1".
y = x + 0 ; y = string "10".
y = x * 1 ; y = number 49 (ASCII '1').
y = eval(x) ; y = number 1.
Code: Select all
.function rev(s)
rev = ""
.for i = 1, i <= strlength(s), ++i
rev += strsub(s, -i, 1)
.loop
.endfunction
; Displays "Hello!"
.echoln rev("!olleH")
Latenite 1 compatibility is going to be fairly important. Brass 3 is quite different, but has been developed in such a way that for the most part it will integrate with Latenite 1 as well as Brass 1 currently does.
The current compilation process is to set a bunch of environment variables then invoke a compile command file (.cmd), which in turn runs Brass with a shedload of command-line arguments.
Brass 3 just takes one command-line argument - a project filename. Thus, the workaround is to do this;
- Delete/move/rename existing Brass.exe in "Compile" directory.
- Create a "Brass3" directory inside "Compile".
- Copy new Brass.exe, plugins to Compile\Brass3
- Copy CreateBrassProj.exe and CreateBrassProj.proj to Compile\Brass3.
- Create Compile\Brass.cmd that invokes CreateBrassProj.exe and Brass.exe.
Code: Select all
"%COMPILE_DIR%\Brass3\CreateBrassProj.exe" Latenite.brassproj %1 %2 %3 %4 %5 %6 %7 %8 %9
"%COMPILE_DIR%\Brass3\Brass.exe" Latenite.brassproj > Nul
In brief; all you will hopefully have to do to get Brass 3 support in Latenite 1 is to copy a few files over and delete the old Brass.exe.
To further enhance compatibility, the Help viewer can output Latenite help files (.xml), resulting in highlighted Brass 3 directives and functions.
Click for big.
For some more examples ("further reading"): eval(), year(), freadtext(), strtoken(), envvars, .asciimap, .clearpage.
*Steals*benryves wrote:Probably because I got the MSDN team to design it for me. (Sorry about the awful CSS/HTML, it was chucked together quickly).Timendus wrote:Why does that look so much better than my documentation?
I think I'm going to steal parts of it from you
http://timendus.student.utwente.nl/~vera/asmdoc/
(See test.asm, others are pretty much empty)
The HTML/CSS really is a mess.. So I just copied some of the colors and a bit of css here and there, tried to make it look professional but not an exact copy. I'm not sure about the extendable tree. It's not necessary for now, and probably not worth my time to redo that at the moment. So maybe later.
It should have syntax highlighting though. Any ideas on how we could do that with XSL..?
(Sorry for spamming in your topic, by the way The string functions and Latenite integration look really cool, almost makes me regret not using Windows anymore )
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
Cool stuff, but renders very strangely in Opera 9.
Latenite 1 compatibility is just a temporary hack, ultimately I'd like to build a .NET-based IDE (Latenite 1 uses a lot of Win32 code). Hopefully Mono's WinForms will be up to the task.
Latenite 1 compatibility is just a temporary hack, ultimately I'd like to build a .NET-based IDE (Latenite 1 uses a lot of Win32 code). Hopefully Mono's WinForms will be up to the task.
That is weird... I'll look into it. Hadn't tested in Opera yet.benryves wrote:Cool stuff, but renders very strangely in Opera 9.
(Actually, I've only got Firefox here and I'm too lazy to install anything else when I've got my Grande Browser Compatibility Testsuite all set up at home )
WhiiiiiieeLatenite 1 compatibility is just a temporary hack, ultimately I'd like to build a .NET-based IDE (Latenite 1 uses a lot of Win32 code). Hopefully Mono's WinForms will be up to the task.
Can't want to transparently wobble Latenite in my Beryl/Compiz!
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS