Basic assembler dialects
Pages: 1 2
nemo (145) 2546 posts |
I’ve spent a little time evaluating this but I don’t have any spare cycles to actually do it right now. There are some patches for Basic that give it the ability to assemble 6502 or 6809 code. Other patches have extended the ARM assembler’s capabilities. Various official versions of Basic over the years have supported different ARM instruction groups… or not. It’s not ideal really. I propose a little refactoring, a new bit of syntax, and a whole lot of extra functionality: [FOR"6502":LDA #0:] [FOR"6809":LDB #&FF:] [FOR"ARM":MOV R0,#-1:] OPT, ALIGN, FN and the various data builders are implemented in Basic, along with (optionally) a default assembler for the platform (ie Z80 Basic has a Z80 assembler), plus the new pseudo instruction FOR. It issues a Service Call (or so forth – execute a sysvar if no response etc) and hence finds the named assembler, provided by another module. The assembler module is an intimate friend of Basic, and is allowed full memory access and a limited code interface much like CALL. It is called per instruction, and parses up to the next : or CR, returning a length in R2 and the bytes in STRACC (or it can assemble direct if it is prepared to inspect and update ASSOPT, P, O and L appropriately, but it’s unlikely to be necessary). The built-in support then inserts those bytes, exactly as it already does. There isn’t much code to change in Basic – the assembler is extremely localised. Errors returned with V set and a 16bit number just as currently. Basic will need to store a pointer to its current assembler. That’s about it. Advantages: • Additional target processors can be supported without having to patch the many Basics Naturally this is somewhat influenced by Rebol’s ‘dialects’. I commend it to the House. |
nemo (145) 2546 posts |
I lied. It was such an interesting idea I knocked up a prototype. I’ve made a version of 1.29 with support for dialects and no ARM assembler. Then I made an assembler module that provides only one instruction – UP – that works like EQUS except it uppercases the text as it builds it. And it works! This shows the assembler working, with no ARM instructions and, to begin with, no UP instruction either. Then I select the Assembler Dialect with FOR (this assembler is called “UP” which is a mistake – I should have called it something else for clarity, sorry), at which point I can then use the UP mnemonic. Note that when I use UP with no parameter I get an appropriate error, even though this is two separate modules communicating over a thin interface. There are interesting questions as to whether assemblers can be cumulative – ie, can multiple modules all recognise a dialect and each implement some of it? Or should it be one dialect at a time for clarity? |
Rick Murray (539) 13840 posts |
Ooh, I like this!
I wonder if providing multiple modules would permit each to do one thing well – there could be one for ARM32, one for FPE, one for VFP, one for NEON. It might sound a little messy but it would permit each module to do its task well without trying to stuff in all sorts of assorted things in order to provide “one true assembler” to cover current RISC OS targets. I like the mix and match approach, and I really like the concept. |
nemo (145) 2546 posts |
Yeah this was my original concept. Seems a shame that adding NEON say requires duplicating all the existing stuff. Assemblers are basically atomic and stateless anyway. However, you also want to be able to revoke dialects, it can’t be everything at the same time. So although it’s obvious that It’s trivial with different code regions as you can switch between dialects (or have no dialect with |
nemo (145) 2546 posts |
OK, I’ve settled on a protocol: • Dialects can be loaded from disc on demand via sysvars There is a distinction between Dialect names and Assembler names. Hence the dialect “Armv8-A” could cause the “ARM-A64” assembler to be selected (amongst others). It is even possible for a module to recognise a dialect name and select the necessary assemblers, even if the assemblers themselves didn’t recognise the dialect name. It should be possible for Basic to subdivide its built-in assembler and respond to various Dialects too. However, Basic maintains a linked list of registered assemblers, much like a list of string vars. These are named by Assembler, not by Dialect. As well as workspace for the Assembler, these nodes contain an Active flag. When When If nothing registers as a result of the Service Call, Basic looks for a System Variable called If the statement continues with When an Assembler registers, Basic checks its list of registered Assembler nodes and if it isn’t a known one, creates a new node. Either way, the node is marked Active and the list reordered so this node follows any existing Active Assemblers. When the workspace address is returned to the Assembler, it is also told whether this is a new allocation. Basic recognises the data building instructions plus OPT, ALIGN and FOR pseudo instructions. For anything else, if there are no Active Assemblers then the built-in assembler is used. Otherwise, each Active Assembler is called in order until one handles the instruction. If none do, that’s an error.
Assemblers should NOT allocate their own workspace, as Basic can be killed in so many exciting and innovative ways, and they would not be closed. Assemblers are usually atomic per instruction, and hence stateless, but the optional workspace I’m not convinced that Comments welcome. |
Rick Murray (539) 13840 posts |
How does this go if you hop in and out of assembler for – for instance – setting up data blocks in line with the assembled code (useful also for defining labels)…? Maybe FOR "" should be used as the way to explicitly close down active assemblers? |
nemo (145) 2546 posts |
The problem is that there’s no way of telling whether a Having said that, it could restart those Assemblers at the next [OPTopt%:FOR"ColourWord" RED 0 GRN 0 BLU 0 RED 255 GRN 255 ] …but I take the point that the very next bit of code might be Another question is whether one would want to be able to [OPTopt%:FOR"ARM" SWI "Emulate_Inline6502" FNthe6502code(opt%) ALIGN SWI "OS_WriteS" = " That was 6502 code just there" = 0 ALIGN MOV PC, R14 ] ... DEFFNthe6502code(opt%) LOCAL FOR [OPTopt%:FOR"6502" LDA #ASC"W" JSR &FFEE LDA #ASC"o" JSR &FFEE JSR &FFEE LDA #ASC"t" JSR &FFEE RTS ] ="" I hope everyone says “no”, because it wouldn’t be simple. |
nemo (145) 2546 posts |
I can’t remember the last time I used
|
Rick Murray (539) 13840 posts |
I was going to say “A FOR should apply until a different one replaces it”, but then I am thinking that one might want to Maybe it should be extremely explicit, like:
And if that looks clumsy, well, who’s the one trying to build code for 6502 and ARM at the same time? Just be happy it’s (potentially?) possible. :-)
I have, but it’s been a beeelion years since I’ve used BASIC. Most of my assembler (which is ever-diminishing) is objasm these days. Umm… Um… Oh, I remember what it was. It was a library that took FP instructions as strings and returned words for inserting into the code (in the days before BASIC had FP support). Something like
My comment regarding this was also because it can be useful to drop out of assembler to insert the contents of a file loaded from disc (sprite, data, window def, etc).
I’m just wondering if there should be an option that if there are Active Assemblers, they will be called in order. If none of them handle the instruction, it will be handed to the built-in assembler (but optionally – it’s useless if you’re trying to build Z80 code!). In this way, one can begin extending the sort of things BASIC is capable of doing without first writing a complete copy of the existing assembler.
Hmm… Theoretical question: How would one interwork Thumb code? The instruction set is very similar to ARM32. Explicit change of state? I wonder how other assemblers do it (I don’t think objasm can, can it?). |
nemo (145) 2546 posts |
Indeed, so
Well yes, but
Which, ironically enough, one could do from inside such an
Yes, that is exactly how it works. So
Yes, that is the point. And hence
Assuming a suitable Assembler, I’m noticing no definitive answer to the |
Rick Murray (539) 13840 posts |
The point of the above musings were to see if it was really needed. Explicitly setting what “should be” either side of a block of something-else code ought to suffice given that it’s probably going to be a niche thing to want to support two different non-coexisting architectures in the same file. ;-) |
Rick Murray (539) 13840 posts |
A little something that crept into mind. Your ARM/6502 example. On the way out of 6502, what’s P%? I’m guessing the ARM mode assembler should force word alignment? As part of its entry? That way, a label prior to an instruction will point to the correct place…? |
nemo (145) 2546 posts |
Behaviour unchanged, so this: [FOR"ARM"AND"6502" MOV R0,#0 LDA #1 .u: MOV R0,#2 is identical to this: [ MOV R0,#0 EQUW &01A9 .u: MOV R0,#2 In other words, the ARM assembler already forces alignment at the next ARM instruction.
Define “correct”. |
Rick Murray (539) 13840 posts |
Just remembering that’s what trashed the Zap Obey handler – the code label followed data and wasn’t aligned, nothing cared until later revisions of ARMv7… [FOR"ARM"AND"6502" I think my head just exploded. |
nemo (145) 2546 posts |
It would be amusing to write an Assembler that created ARM instructions from 6502 mnemonics… just to mess with people’s heads. Meanwhile, I wasn’t planning on writing an actual 6502 Assembler today, but I seem to be doing so. Where did my life go wrong? |
Steve Pampling (1551) 8170 posts |
A subconscious drive to avoid doing the Keyboard / Territory / Wimp work you half, or more, talked yourself into? :) |
John Williams (567) 768 posts |
You sit there in front of your networked keyboard provoking Nemo into doing more? Good on y’! We need all the help we can get! |
Rick Murray (539) 13840 posts |
Should be doable – can the 6502 do anything that can’t be represented in ARM? On the other hand…
More or less. ;-) |
David Feugey (2125) 2709 posts |
Or to write an Assembler that create ARM instructions from very simple mnemonics. |
Dave Higton (1515) 3525 posts |
I think that’s called “C”. |
David Feugey (2125) 2709 posts |
Why not. But as a Basic dialect. |
nemo (145) 2546 posts |
Steve alleged:
Rick said:
I meant |
nemo (145) 2546 posts |
1. In 2002 I wrote a disassembler for the Sunplus SPC processors, which are 2/3 of a 6502 but with entirely different opcodes. I was doing a thing for Hasbro. Little did I know that a mere 17 years later I would finally get around to writing the assembler to go with it… the 6502 Assembler has suffered delusions of grandeur, and now supports the following Dialects: MOS6501(withdrawn), MOS6502 (6502B Atari, 6502C Atari), MOS6508(CBM900), MOS6510(C64)/MOS7501/MOS8500/MOS8501, 6510T, 6512(B+64), 6513, 6514, 6515, MOS8502 64K + Z register + 16b stack + zp->dir + 46 opcodes MOS65CE02, MOS4510 64K + 12 instr WDC65C02 65C102 65C112 64K + 8 instr 65SC02 65SC12 65SC10265SC112 4K 6503 6505 6506 6513 6515 4K + 8 instr 65SC03 65SC05 65SC06 65SC13 65SC15 65SC103 65SC105 65SC106 65SC115 8K 6504 MOS6507(Atari2600) 6514 8K+ 8 instr 65SC04 65SC07 65SC14 65SC104 65SC107 1MB MOS6509 2MB Hudson HuC6280 (65C02) Ricoh (no BCD) 2A03(NES NTSC), SA07(NES PAL) 16b MOS65802/MOS65816(SNES, AppleIIGS), Ricoh 5A22(SNES), SA1(SNES games - extra instr) Sunplus full 65N02 SPL61A, SPL130A, SPL191A, SPDC256A, SPDC512A, SPDC512B, SPDC1000A, SPDC1000B, SPLB10A Sunplus 65R02 - reduced+BIT+TXA+TAX SPF02A, SPL02C, SPL02D, SPL03B, SPL03C, SPL05A, SPL05B, APL06A, APL06B, APL128A, APLB20A, APLB20A1, APLB21A, SPLB22A, SPLB23A, SPLB24A, SPLB25A, SPLB26A, SPLG01 Sunplus 65S02 - "shrinkage" reduced SPF06A1, SPF18A1, SPF20A, SPF30A1, SPF30B, SPL02A Sunplus code CPU12/CPU18 - reduced+BIT+TAX+TXA SPC*, SPCR*, SPMC*, SPFA64A, SPFA120A, SPL08A, SPL08A1, SPL081A, SPL10A, SPL15A, SPL15B, SPL25B, SPL25C, SPL30A, SPL31A, SPL60A, SPL190A Sorry about that. 2. Also I’ve had an actually good idea: [FOR"EQUBIT" EQU3 7 EQU1 1 EQU4 15 I’m wondering about 3. In light of that, and the limitations of Basic’s [FOR"EQUExtended"AND"" EQUW half%,word%,in%,line% = "Oh yes, we do want this",0 = 1,2,3,4,5,6,7,8,9 4. I’ll also implement my favourite Aasm macro as “AssPBase”: [FOR"PBASE"AND"" .jumptable:PBASE P label1 P routine2 P thing3 ; or with a parameter PBASE modulestart P entry1 P ; this will be 0 regardless P entry2 which, if you haven’t guessed, assemble offsets (from a base address) rather than absolute addresses. Saves a lot of “-modulestart” |
Steve Pampling (1551) 8170 posts |
Good gracious that isn’t normal day wear so it must be your party frock. :) |
Rick Murray (539) 13840 posts |
I know. I just thought I’d take a… different approach… Did you build the 6502 example I gave you? ;-) BTW, feel sorry for those girls. Imagine how many beatings it took to get them to the stage where they could perform such a thing.
I got myself a cheap little arcade game (with 240 built in games) and was kind of blown away by the realisation that it may be a VT16 (Famicom/NES clone) which means it’ll be a 5MHz 6502 core with ~4K RAM and a pile of hardware/DMA for pushing sprites around. http://www.vrt.com.tw/datasheet.htm
But unlike C bitfields, dealing with the actual bits is an exercise for the programmer… :-)
:-) I have two useful macros that I use with objasm – |
Pages: 1 2