flat assembler
Message board for the users of flat assembler.
![]() Goto page 1, 2 Next |
Author |
|
jmg 20 Sep 2016, 23:19
jmg wrote:
expanding on that, I find a small fasmg issue with binary numerics. Code: dd (10000001b shl 22) is accepted as ok, but a 10 char binary string gives an error ? Code: dd (1000000010b shl 22) Surely binary stings to 32 chars or even 64 should be valid ? There may be a case for modula-8 length check, but in this case, the natural field is 10b, so that would make the macro larger than it needed to be. Addit: Just tested latest Version that adds Underscore, and it also fixed this issue. (flat assembler g version 0.98.1474353977) Valid now, are all of the below, a number too large for the field, flags an error. Code: dd (10000000_10b shl 22) dd (1111_1010_0101_0111_0110_0101_0100_0011b) ; dd (1_1111_1010_0101_0111_0110_0101_0100_0011b) ; flags dq (1110_1111_1010_0101_0111_0110_0101_0100_0011_0010_0001b) Looks very good. |
|||
![]() |
|
Tomasz Grysztar 21 Sep 2016, 06:11
jmg wrote: What is a compact/efficient way to add such an optional prefix to fasmg ? Code: iterate <Cond,wxyz>, TEST,1111b macro IF_#Cond? instruction& instruction,wxyz end macro end iterate IF_TEST ADD ParD,ParS ; now becomes ADD ParD,ParS,1111b If you don't want to enable an optional syntax with additional parameter for instructions like ADD, you can also forward this to a variant of instruction in a special namespace, and handle additional parameter there: Code: define Conditioned ; create base symbol for namespace iterate <Cond,wxyz>, TEST,1111b macro IF_#Cond? instruction& Conditioned.instruction,wxyz end macro end iterate namespace Conditioned macro ADD? ParD,ParS,wxyz display `x end macro end namespace macro ADD? ParD,ParS ; the regular instruction can now just forward processing Conditioned.ADD ParD,ParS,1111b end macro |
|||
![]() |
|
jmg 21 Sep 2016, 06:57
Tomasz Grysztar wrote: A first thought that comes to my mind is to create IF_Cond instructions that would convert the condition to an additional argument at the end Thanks. I tried the first form, and it gets very close with the result below - it does not handle the default case of no IF_Test present. ie the opcodes have the optional IF_Test prefix test. In most cases, code does not use the IF_Test conditional - in that case, a default of 1111b is applied to that part of the opcode. Code: macro pcADD? ParD,ParS,ParC dd (100000_0010b shl 22)+(ParC shl 18)+(ParD and 0x1ff) shl 9 + ParS and 0x1ff end macro ; guess this can generate 3+ opcodes, like... iterate <Cond,wxyz>, TEST,1111b,TWO,0010b,THREE,0011b macro IF_#Cond? instruction& instruction,wxyz end macro end iterate ; ~~~~~~~~~~ Test code ~~~~~~~~~~ IF_TEST pcADD 0AH,05H ; now becomes ADD ParD,ParS,1111b OK IF_TWO pcADD 0AH,05H ; now becomes ADD ParD,ParS,0010b OK IF_THREE pcADD 0AH,05H ; now becomes ADD ParD,ParS,0011b OK ; pcADD 07H,03H ; fails when no Cond prefix ? |
|||
![]() |
|
Tomasz Grysztar 21 Sep 2016, 07:05
jmg wrote:
Code: macro pcADD? ParD*,ParS*,ParC:1111b dd (100000_0010b shl 22)+(ParC shl 18)+(ParD and 0x1ff) shl 9 + ParS and 0x1ff end macro |
|||
![]() |
|
jmg 21 Sep 2016, 07:15
Tomasz Grysztar wrote: In this case you could just do it like this: Cool, It did look close - this fasmg certainly is powerful ![]() |
|||
![]() |
|
jmg 21 Sep 2016, 21:01
Progress Update : This structure seems to be working.
Takes ~2.2s to generate largest possible ASM image for Parallax P8X32A. Code: ; Common Conditional, Dest, Source opcode parts ; - can add range checks here ParD,ParS are simply masked here, and ParC is internally defined as always 4b macro gpCDS? ParD*,ParS*,ParC:1111b pCDS = (ParC shl 18)+(ParD and 0x1ff) shl 9 + ParS and 0x1ff end macro ; Test a couple of P8X32A Opcodes, simpler forms. ; ADD 100000 001i cccc ddddddddd sssssssss macro pcADD? ParD*,ParS*,ParC:1111b gpCDS ParD,ParS,ParC match #data, ParS dd (100000_0011b shl 22) + pCDS else dd (100000_0010b shl 22) + pCDS end match end macro ; SUB 100001 001i cccc ddddddddd sssssssss macro pcSUB? ParD*,ParS*,ParC:1111b gpCDS ParD,ParS,ParC match #data, ParS dd (100001_0011b shl 22) + pCDS else dd (100001_0010b shl 22) + pCDS end match end macro ; ~~~~~~~ Generate all 32 IF_ forms ~~~~~~~~~~~~~~ ; This expansion is done once, and then passes rest of line to another macro iterate <Cond,wxyz>,\ ALWAYS,1111b,NEVER,0000b,E,1010b,NE,0101b,A,0001b,B,1100b,AE,0011b,BE,1110b,C,1100b,NC,0011b,\ Z,1010b,NZ,0101b,C_EQ_Z,1001b,C_NE_Z,0110b,C_AND_Z,1000b,C_AND_NZ,0100b,NC_AND_Z,0010b,NC_AND_NZ,0001b,\ C_OR_Z,1110b,C_OR_NZ,1101b,NC_OR_Z,1011b,NC_OR_NZ,0111b,Z_EQ_C,1001b,Z_NE_C,0110b,Z_AND_C,1000b,\ Z_AND_NC,0010b,NZ_AND_C,0100b,NZ_AND_NC,0001b,Z_OR_C,1110b,Z_OR_NC,1011b,NZ_OR_C,1101b,NZ_OR_NC,0111b macro IF_#Cond? instruction& instruction,wxyz end macro end iterate TestSimpler = 0 if TestSimpler = 1 ;Times : Full 8 COG -> 2 passes, 2.2 seconds, 16487 bytes. rept 511*8 pcADD 07H,03H ; Comment end rept else ; Times: ; Full 32 IF_ -> 2 passes, 2.2 seconds, 16455 bytes. ; Added '#' -> 2 passes, 2.2 seconds, 16455 bytes. LoopC = (512/15) ; 15 lines - fill all 8 COGs to allow speed tests rept LoopC*8 IF_E pcADD 0AH,05H ;Comment IF_NE pcADD 0AH,#05H ;Comment IF_A pcADD 0AH,05H ;Comment IF_B pcADD 0AH,05H ;Comment pcADD 07H,03H ;Comment IF_E pcSUB 0AH,05H ;Comment IF_NE pcSUB 0AH,#05H ;Comment IF_A pcSUB 0AH,05H ;Comment IF_B pcSUB 0AH,05H ;Comment pcSUB 07H,03H ;Comment IF_E pcADD 0AH,#05H IF_NE pcADD 0AH,05H IF_A pcADD 0AH,#05H IF_B pcADD 0AH,#05H pcADD 07H,#03H end rept end if |
|||
![]() |
|
jmg 21 Sep 2016, 23:36
Prefix is working nicely...
Now I'd appreciate some tips on the best way to manage Opcode suffix options.., which map to the ZCR opcode bits. Good news is only WZ WC NR are legal, (any case) bad news is they can be in any combination or order. Code: ; ZCRi ;XOR 011011 001i cccc ddddddddd sssssssss tXOR 0AH,#04H ; Suffix Comment IF_Z tXOR 0AH,#05H ;ZCR = 001, default IF_NZ tXOR 0AH,#05H WC ;C field set 011 IF_A tXOR 0AH,#05H WZ ;Z field set 101 IF_B tXOR 0AH,#05H NR ;R field clr 000 IF_C tXOR 0AH,#05H WZ,WC ;Z,C both set 111 IF_C tXOR 0AH,#05H WC,wz ;Z,C both set 111 Same result IF_C tXOR 0AH,#05H WZ,NR ;Z set, R clr 100 IF_C tXOR 0AH,#05H NR,WZ ;Z set, R clr 100 Same result etc IF_C tXOR 0AH,#05H wc,NR ;C set, R clr 010 IF_NC tXOR 0AH,#05H WZ,WC,nr ;Z,C set, R clr 110 etc I have a subset working, somewhat.... Code: tXOR 0AH,#05H ; Suffix Comment ;if TestSuffix=1 tXOR 0AH,#05H,WC ;C field set 011 tXOR 0AH,#05H,WZ ;Z field set 101 tXOR 0AH,#05H,NR ;R field clr 000 tXOR 0AH,#05H, wc ;C field set 011 tXOR 0AH,#05H, wz ;Z field set 101 tXOR 0AH,#05H, nr ;R field clr 000 Caveats are this form needs an added semicolon, which is best avoided. - plus the IF_ handling above tangles with following params, so I removed that for testing. Ideal goal is this syntax Code: IF_NC tXOR 0AH,#05H WZ,WC,nr ;Z,C set, R clr 110 etc |
|||
![]() |
|
Tomasz Grysztar 22 Sep 2016, 06:41
You could do it with a long sequence of matches for every possible combination, but that would be slow and considering the time it took to assemble your previous sample on your machine it is perhaps better to avoid such solution. Therefore I'd suggest defining the suffixes as symbolic values containing some special combination of symbols that can be easily matched and cut off from the base instruction:
Code: NR equ :+:001b WC equ :+:010b WZ equ :+:100b Code: macro IF_#Cond? tail& match instruction :+:suffix, tail local buffer,flags buffer equ suffix flags = 0 while 1 match first =, :+:next, buffer flags = flags or first buffer equ next else flags = flags or buffer break end match end while flags = flags xor 1 ; NR is reversed base.instruction,wxyz,flags else base.tail,wxyz end match end macro |
|||
![]() |
|
jmg 22 Sep 2016, 07:12
Tomasz Grysztar wrote: Therefore I'd suggest defining the suffixes as symbolic values containing some special combination of symbols that can be easily matched and cut off from the base instruction: It coughs on the :+: and the manual has no examples ? Or, was that a placekeeper for some special String prefix combination ? Tomasz Grysztar wrote:
When I tried a general form with wxyz and flags both as params, the macro passing seemed to get confused as one or the other may be present alone ? Rather than params, I may try a globals approach ? |
|||
![]() |
|
Tomasz Grysztar 22 Sep 2016, 07:35
jmg wrote:
jmg wrote: When I tried a general form with wxyz and flags both as params, the macro passing seemed to get confused as one or the other may be present alone ? Code: macro example ParD*,ParS*,ParC:1111b,ParF:001b db ParD,ParS,ParC,ParF end macro example 0Ah,05h ; two defaults example 0Ah,05h,1001b ; default ParF example 0Ah,05h,,111b ; default ParC example 0Ah,05h,0,111b ; no defaults |
|||
![]() |
|
Tomasz Grysztar 22 Sep 2016, 07:44
jmg wrote: It coughs on the :+: and the manual has no examples ? Actually, your comment gave me an inspiration for a better idea: Code: define NR SUFF -001b define WC SUFF 010b define WZ SUFF 100b define SUFF Code: macro IF_#Cond? tail& match instruction =SUFF suffix, tail local flags flags = 001b iterate flag,suffix if flag >= 0 flags = flags or flag else flags = flags and not -flag end if end iterate base.instruction,wxyz,flags else base.tail,wxyz end match end macro |
|||
![]() |
|
jmg 22 Sep 2016, 07:55
Tomasz Grysztar wrote: You can choose the sequence of symbols freely, they are only used here so that the MATCH inside the macro is able to detect boundary between regular arguments and suffix Hmm, when I use the exact Code: NR equ :+:001b It spits 'invalid expression' on that line ? Tomasz Grysztar wrote:
Ah, ok, I can see that works with ,, to tell the ASM where to place them, but ideally I want to parse white space(s) after the IF_Cond, and another white space(s) before the optional WC,WZ,WR , so that may be better to define a default, and at the end of each opcode, set back to default. Then, empty fields update as they appear, and either or both missing, has no effect on macro param order. I think the flag-scan outline has promise, if I can get past the error messages... I'm unclear on 'tail', 'suffix', 'base' and 'instruction' word interactions in the example, they do not seem to be keywords ? |
|||
![]() |
|
jmg 22 Sep 2016, 08:07
Tomasz Grysztar wrote: Actually, your comment gave me an inspiration for a better idea: That also solves the error message.... Tomasz Grysztar wrote:
That seems to cough on base.instruction, but I think with globals, I can use a single instruction call and get the white space tolerance ? |
|||
![]() |
|
Tomasz Grysztar 22 Sep 2016, 08:17
jmg wrote: Hmm, when I use the exact jmg wrote: That seems to cough on base.instruction Code: define base namespace base macro pcADD? ParD*,ParS*,ParC:1111b,ParF:001b ; ... end namespace jmg wrote: I'm unclear on 'tail', 'suffix', 'base' and 'instruction' word interactions in the example, they do not seem to be keywords ? |
|||
![]() |
|
jmg 22 Sep 2016, 10:16
Good progress, all the complex cases now work, but the no IF_ case needs work.
now gParC is global, I think it would be cleaner to push the iterate flag,suffix block into the G_CDS macro, ( to avoid duplication) which I think means ParS*& ? Code: define NR SUFF -001b define WC SUFF 010b define WZ SUFF 100b define SUFF gParC = 1111b ; default gZCR = 001b macro G_CDS? ParD*,ParS* gCDS = (gZCR shl 23) + (gParC and 0xf) shl 18 + (ParD and 0x1ff) shl 9 + ParS and 0x1ff gZCR = 001b ; restore default, after use gParC = 1111b ; restore default, after use end macro ; ZCRi ;XOR 011011 001i cccc ddddddddd sssssssss ; 109876 5432 1098 765432109 876543210 macro qXOR? ParD*,ParS* ; ParC, ZCR now global G_CDS ParD,ParS ; Globals avois WC into ParC match #data, ParS dd (011011_000_1b shl 22) + gCDS else dd (011011_000_0b shl 22) + gCDS end match end macro iterate <Cond,wxyz>,\ ALWAYS,1111b,NEVER,0000b,E,1010b,NE,0101b,A,0001b,B,1100b,AE,0011b,BE,1110b,C,1100b,NC,0011b,\ Z,1010b,NZ,0101b,C_EQ_Z,1001b,C_NE_Z,0110b,C_AND_Z,1000b,C_AND_NZ,0100b,NC_AND_Z,0010b,NC_AND_NZ,0001b,\ C_OR_Z,1110b,C_OR_NZ,1101b,NC_OR_Z,1011b,NC_OR_NZ,0111b,Z_EQ_C,1001b,Z_NE_C,0110b,Z_AND_C,1000b,\ Z_AND_NC,0010b,NZ_AND_C,0100b,NZ_AND_NC,0001b,Z_OR_C,1110b,Z_OR_NC,1011b,NZ_OR_C,1101b,NZ_OR_NC,0111b macro qIF_#Cond? tail& gParC = wxyz ; new CC value match instruction =SUFF suffix, tail local flags flags = 001b iterate flag,suffix ; comma delimited list if flag >= 0 flags = flags or flag else ;NR flags = flags and not -flag end if end iterate gZCR = flags instruction ; trimmed of tail else gZCR = 001b tail ; no-trim, tail is the opcode end match end macro end iterate qIF_Z qXOR 0AH,#05H WC ;C field set 011 qIF_Z qXOR 0AH,#05H WZ ;Z field set 101 qIF_Z qXOR 0AH,#05H WZ,WC ;ZC field set 111 qIF_Z qXOR 0AH,#05H WC,WZ ;ZC field set 111 qIF_Z qXOR 0AH,#05H NR ;R field clr 000 qXOR 0AH,#05H qXOR 0AH,#05H WC ; << this case fails, can we push iterate flag,suffix into G_CDS? qIF_ALWAYS qXOR 0AH,#05H qIF_ALWAYS qXOR 0AH,#05H WZ qIF_ALWAYS qXOR 0AH,#05H WZ,WC qIF_ALWAYS qXOR 0AH,#05H WZ,WC,NR ; field checks dd (001b shl 23) ; default dd (101b shl 23) ; wz dd (111b shl 23) ; wz wc dd (000b shl 23) ; nr |
|||
![]() |
|
Tomasz Grysztar 22 Sep 2016, 12:30
jmg wrote: now gParC is global, I think it would be cleaner to push the iterate flag,suffix Code: macro G_CDS? D*,S_Suffix*& ParD = D gZCR = 001b match S =SUFF suffix, S_Suffix ParS = S local flags iterate flag,suffix ; comma delimited list if flag >= 0 gZCR = gZCR or flag else ;NR gZCR = gZCR and not -flag end if end iterate else ParS = S_Suffix end match gCDS = (gZCR shl 23) + (gParC and 0xf) shl 18 + (ParD and 0x1ff) shl 9 + ParS and 0x1ff gZCR = 001b ; restore default, after use gParC = 1111b ; restore default, after use end macro ; ZCRi ;XOR 011011 001i cccc ddddddddd sssssssss ; 109876 5432 1098 765432109 876543210 macro qXOR? ParD*,ParS*& ; ParC, ZCR now global G_CDS ParD,ParS ; Globals avois WC into ParC match #data, ParS dd (011011_000_1b shl 22) + gCDS else dd (011011_000_0b shl 22) + gCDS end match end macro |
|||
![]() |
|
jmg 22 Sep 2016, 20:57
Thanks, that's great! - I've now moved it, & passes all tests...
Code: ; ~~~~~~~~~~~~~~ Now Expanded to support Suffix too.. ~~~~~~~~~~~~~~~~~ ;web suggestion define NR SUFF -001b define WC SUFF 010b define WZ SUFF 100b define SUFF gParC = 1111b ; default, globalV init macro G_CDS? ParD*,S_Suffix*& ; & for ParS and any suffix controls gZCR = 001b ; default match S =SUFF suffix, S_Suffix ;splits S, ParS = S local flags iterate flag,suffix ; comma delimited list if flag >= 0 gZCR = gZCR or flag else ;NR gZCR = gZCR and not -flag end if end iterate else ParS = S_Suffix end match gCDS = (gZCR shl 23) + gParC shl 18 + (ParD and 0x1ff) shl 9 + ParS and 0x1ff gParC = 1111b ; restore global default, after use end macro ; ZCRi ;XOR 011011 001i cccc ddddddddd sssssssss ; 109876 5432 1098 765432109 876543210 macro qXOR? ParD*,ParS*& ; ParC now global, ZCR via any suffix G_CDS ParD,ParS match #data, ParS dd (011011_000_1b shl 22) + gCDS else dd (011011_000_0b shl 22) + gCDS end match end macro ; ~~~~~~~~~ Build 32 IF_ variants ~~~~~~~~~~~~ iterate <Cond,wxyz>,\ ALWAYS,1111b,NEVER,0000b,E,1010b,NE,0101b,A,0001b,B,1100b,AE,0011b,BE,1110b,C,1100b,NC,0011b,\ Z,1010b,NZ,0101b,C_EQ_Z,1001b,C_NE_Z,0110b,C_AND_Z,1000b,C_AND_NZ,0100b,NC_AND_Z,0010b,NC_AND_NZ,0001b,\ C_OR_Z,1110b,C_OR_NZ,1101b,NC_OR_Z,1011b,NC_OR_NZ,0111b,Z_EQ_C,1001b,Z_NE_C,0110b,Z_AND_C,1000b,\ Z_AND_NC,0010b,NZ_AND_C,0100b,NZ_AND_NC,0001b,Z_OR_C,1110b,Z_OR_NC,1011b,NZ_OR_C,1101b,NZ_OR_NC,0111b macro qIF_#Cond? instruction& gParC = wxyz ; apply CC value, now global instruction end macro end iterate ; ~~~~~~~~~ Test coverage ~~~~~~~~~~~~ qIF_Z qXOR 0AH,#05H WC ;C field set 011 qIF_Z qXOR 0AH,#05H WZ ;Z field set 101 qIF_Z qXOR 0AH,#05H WZ,WC ;ZC field set 111 qIF_Z qXOR 0AH,#05H WC,WZ ;ZC field set 111 qIF_Z qXOR 0AH,#05H NR ;R field clr 000 qXOR 0AH,#05H qXOR 0AH,#05H WC ; Fixed with push iterate flag,suffix into G_CDS? qIF_ALWAYS qXOR 0AH,#05H qIF_ALWAYS qXOR 0AH,#05H WZ qIF_ALWAYS qXOR 0AH,#05H WZ,WC qIF_ALWAYS qXOR 0AH,#05H WZ,WC,NR |
|||
![]() |
|
jmg 14 Oct 2016, 01:29
Cleaning this up a little for more tests, and I find an unexpected speed gain..
;0.99 ; Listing ON -> 2 passes, 2.4 seconds, 16547 bytes. 266k LST ; Listing OFF -> 2 passes, 0.4 seconds, 16547 bytes. 80 byte LST ; Clean-up, removed obsolete test code, placed macros first, - ? much faster, maybe due to 1 pass now ? ; 1 pass, 1.4 seconds, 16464 bytes. 251k LST file ; ; more edits ; 1 pass, 1.2 seconds, 16464 bytes. 12k source 251k LST file ; 1 pass, 1.2 seconds, 16464 bytes. 30k source (+18k comments to check file read speed ) ; 1 pass, 0.2 seconds, 16464 bytes. LST off, still ~ 6x slower with LST on. File size created shrank just slightly in the clean-up, but the speed doubled. Not quite what I expected ? I guess this means each pass adds the same time to the assembly ? - but the LST seems to dominate, and that is exactly the same in 1 or 2 passes ? |
|||
![]() |
|
Tomasz Grysztar 14 Oct 2016, 06:06
In fasmg additional passes are only very slightly faster than the first one, so the total time is roughly the multiple of a single pass. In fasm 1 it was different, since it had a separate preprocessor stage after which the passes were performed by pre-compiled bytecode, so additional passes did not add that much time. But to provide the kind of features that fasmg has the other approach was needed.
|
|||
![]() |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.