flat assembler
Message board for the users of flat assembler.

Index > Main > Anonymous labels not enough, need anonymous OPCODES

Goto page Previous  1, 2, 3  Next
Author
Thread Post new topic Reply to topic
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
Control+Fed? What's that?


Hold down control and press f to find out...

Quote:
Sometimes this isn't possible, and you are not considering what I said: if I want to repeat the same code many times.


Why isn't it possible? And i did consider what you said. Every opcode in your program does something, every section does something, so i find it hard to believe some one can't come up with a half creative name.

Quote:
Also, HLL programmers don't use named labels when they program loops and still don't get confused!...


That's cause they enclose in brackets. They don't see the jmp and cmp and such.

Quote:
For example, if I'm processing a raw command arguments string, I need to catch many tokens that can separate the arguments, so I can't use "repne scasb". Now suppose that I need to repeat this same portion of code many times. WHAT different names am I supposed to give the loop?


Personnally, i'd use the same loop and just change the base to the address of each argument and use a conditional jump for the number of remaining strings.

Quote:
Can you point me to some code that uses plenty of anonymous labels for me to make my own read test?


Don't have any links handy. I usually don't think much of code that abuses them. Though, if you'd like i could search icz's site for some non-fasm examples.
Post 02 Jul 2007, 21:22
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo
Here's FIRE.ASM from the latest OctaOS, see if you like it. Wink

Code:
LANG OCTASM,0.1 \\RD\OCTA.ASM
{gui\new\t3(320,240,"%nb fire")
edi=[window] b[edi+gui\flags]|=4 ;window resizable
 wait_ms1(40) edi=Paleta
# stosd eax+=40100h cmp ah,63 jc <1
# stosd eax+=0fd0002h inc ah jns <1
# stosd inc al ah-=2 jnz <1
#l0 ebp=[winx] ecx=ebp ecx<<=7
 ecx=ecx+ebp*2 edi=[img]
 mresize() [img]=edi
#l1 edi=ebp edi<<=7 edi+=[img]
 ecx=ebp eax=[rnd] ecx>>=2
# ebx=eax-1 rol eax,9 ebx-=eax
 eax-=ebx stosd loop <1
 [rnd]=eax edi=[img] ecx=ebp ecx<<=7
# eax=b[edi-1+ebp] bx=[edi+ebp]
 al+=bl adc ah,0 al+=bh adc ah,0
 al+=[edi+ebp*2] adc ah,0 eax>>=2
 eax-=1 adc al,0 stosb loop <1
 al=11 setvideofuncion() d[bmp]=[img]
 d[paleta]=Paleta esi=[winy] ebx=esi
 ebx>>=7 edx=esi edx&=127 eax=0
 edx-=126 esi=128 ecx=ebp jmp >2
# d[bmp]-=ebp inc edx
# lh2() dec bh jns <2
# bh=bl inc edx dec esi jnz <2
# getd() jnc >1
 wait_ms2(40) jnc l1
 del_msg() cmp [winx],ebp je <1 jmp l0
# edi=[img] free() ret
D(rnd,img) #Paleta rb 1024}
    
Post 02 Jul 2007, 23:17
View user's profile Send private message Visit poster's website Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
What the heck? Can something that crazy actually compile?
Post 03 Jul 2007, 07:43
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
r22



Joined: 27 Dec 2004
Posts: 805
r22
rugxulo, thank you for helping to show that a standard assembler syntax (even if its just for x86) would be a VERY GOOD thing.
Post 03 Jul 2007, 13:04
View user's profile Send private message AIM Address Yahoo Messenger Reply with quote
Jeronimus Linuxius



Joined: 28 Jun 2007
Posts: 37
Jeronimus Linuxius
kohlrak wrote:
Quote:
Control+Fed? What's that?


Hold down control and press f to find out...


So do you really think that opening the find window and writing the label name makes it simpler to deal with local labels than with anonymous?

Quote:

Quote:
Sometimes this isn't possible, and you are not considering what I said: if I want to repeat the same code many times.


Why isn't it possible? And i did consider what you said. Every opcode in your program does something, every section does something, so i find it hard to believe some one can't come up with a half creative name.


Difficult because at some point you may need to express similar ideas in more than one label.

Quote:
Quote:
Also, HLL programmers don't use named labels when they program loops and still don't get confused!...


That's cause they enclose in brackets. They don't see the jmp and cmp and such.


Of course, but if they enclose groups of statements in brackets (which don't have names), what's the problem if an asm programmer encloses groups of instructions in anonymous labels? That's just a matter of indentating the anonymous labels differently from normal code and from other labels.

Quote:
Quote:
For example, if I'm processing a raw command arguments string, I need to catch many tokens that can separate the arguments, so I can't use "repne scasb". Now suppose that I need to repeat this same portion of code many times. WHAT different names am I supposed to give the loop?


Personally, I'd use the same loop and just change the base to the address of each argument and use a conditional jump for the number of remaining strings.


Sometimes we need to alternately test for a different set of characters, and this can complicate things...

And if you have only two arguments, there is no need to go into branching...


I don't know why, but asm programmers, and C's too, like their languages because the respective compilers don't try to prevent them from making certain things that would be unacceptable in other languages.
Now, I don't understand what's your problem with anonymous labels. If you don't need them, that's your busyness, but I think their absence is a lack...
One if the features that made me switch from NASM to FASM was the anonymous labels.

JJ
Post 03 Jul 2007, 18:06
View user's profile Send private message MSN Messenger Reply with quote
Jeronimus Linuxius



Joined: 28 Jun 2007
Posts: 37
Jeronimus Linuxius
rugxulo wrote:
Here's FIRE.ASM from the latest OctaOS, see if you like it. ;)

Code:
(...)    


What's this shit???

JJ
Post 03 Jul 2007, 18:08
View user's profile Send private message MSN Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
Jeronimus Linuxius wrote:

Of course, but if they enclose groups of statements in brackets (which don't have names), what's the problem if an asm programmer encloses groups of instructions in anonymous labels? That's just a matter of indentating the anonymous labels differently from normal code and from other labels.

If you need to nest a for or while loop in C, you "just do it". If you do it in assembly with anonymous labels, you need to fix up your previous outer loop control since it would otherwise refer to the new inner loop.

Better to keep your functions relatively short, use meaningful names, and utilize the fact that any assembler worth it's salt supports local labels.

For other uses where you might advocate anonymous labels, macros can be utilized instead (and are better than mindless copy-paste duplication anyway).
Post 03 Jul 2007, 23:15
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid
Quote:
For other uses where you might advocate anonymous labels, macros can be utilized instead (and are better than mindless copy-paste duplication anyway).

i wouldn't agree here. For simple small jump-over-something, anonymous label looks better than if to me:

Code:
sub ebx, eax
jnb @f
mov ebx, 0 ;set to 0 in case of underflow
@@:    


Code:
sub ebx, eax
.if not CARRY?
  mov ebx, 0
.endif    
Post 03 Jul 2007, 23:26
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
So do you really think that opening the find window and writing the label name makes it simpler to deal with local labels than with anonymous?


Yelp...

Quote:
Difficult because at some point you may need to express similar ideas in more than one label.


I've come accross this situation once for multiple window procs. For when i don't handle a message, i usually name a lable such as "go" or "notsupported." Though, i've found that in a situation like that, you could just add the name of the window or the proc for the window infront of the lable.

Quote:
Of course, but if they enclose groups of statements in brackets (which don't have names), what's the problem if an asm programmer encloses groups of instructions in anonymous labels? That's just a matter of indentating the anonymous labels differently from normal code and from other labels.


The fact that brackets keep code together, annonymous lables have a tendancy to sprawl themselves all out over a large distance of code.

Quote:
Sometimes we need to alternately test for a different set of characters, and this can complicate things...


You can always set the base to the base of the string.

Quote:
Now, I don't understand what's your problem with anonymous labels. If you don't need them, that's your busyness, but I think their absence is a lack...


The fact that we still have to read it. You may be writing it, but we end up reading it.

Quote:
i wouldn't agree here. For simple small jump-over-something, anonymous label looks better than if to me:


Small jumps usually aren't a major problem... But how often do we have small jumps?
Post 04 Jul 2007, 05:28
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid
Quote:
Small jumps usually aren't a major problem... But how often do we have small jumps?

pretty often Wink
Post 04 Jul 2007, 10:36
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
WARNING: OFF TOPIC PARAGRAPH - Well how big are they? One op or more when they're freaquent? From what i've been told by a few docs, jmps clear the prefetch queue (i think that's what it was called) every time you use them. This is deffinately a topic for another thread, but perhaps it would be slightly more speed efficient for that reson (though not very space efficient) to start implimention of conditional operations, such as movinb (move if not below) which could follow a cmp (verses compairing and conditionals in one operation which i feel dosn't allow as much freedom, but to everyone his own). Though, this is all based on old documentation.

Quote:
pretty often


I seldom have small jumps, perhaps why i'm so against them. Though, i can't argue with annonymous lables for small jumps. I'm just sick of seeing them used for really big jumps, especially when mixed with named lables, some of which are in between the jump. Though, i purpously loose track of such ugly code.
Post 04 Jul 2007, 12:21
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
Jeronimus Linuxius



Joined: 28 Jun 2007
Posts: 37
Jeronimus Linuxius
vid wrote:
Quote:
Small jumps usually aren't a major problem... But how often do we have small jumps?

pretty often ;)


Very well...

JJ
Post 04 Jul 2007, 20:13
View user's profile Send private message MSN Messenger Reply with quote
Jeronimus Linuxius



Joined: 28 Jun 2007
Posts: 37
Jeronimus Linuxius
kohlrak wrote:
WARNING: OFF TOPIC PARAGRAPH - Well how big are they? One op or more when they're frequent? From what i've been told by a few docs, jmps clear the prefetch queue (i think that's what it was called) every time you use them.


I'm not an expert in CPU architecture, but as far as I know, branch predictors are there exactly to prevent this...
I think the opcodes are decoded right when they are fetched and, when a conditional jump is encountered, a theory about whether they are likely to be followed or not is built by the prefetch queue, and the prefetch advances accordingly (if they aren't likely to be followed, the prefetch continues normally, but if they are likely to be followed, the prefetch continues in the target)...

But this prediction algorithm and it's rules vary between processor models, and only with some carefully coded conditional assembly could we take advantage of them and make the code adapt to different generations of CPUs...

Compilers have their own databases, so they are, I suppose, capable of correctly optimizing the loops to the CPU they are asked for...

However, you are not doing a much worse job than what happens with Windows, if you just ignore branch predictors (and a better job if you find a good solution for it Smile, anyway, who doesn't do a better job than microsoft?), cause only microsoft can optimize windows, and I believe that they optimize it to the most widely used processor (which at the moment is Pentium 4, I think)...

Quote:
This is definitely a topic for another thread, but perhaps it would be slightly more speed efficient for that reson (though not very space efficient) to start implimention of conditional operations, such as movinb (move if not below) which could follow a cmp (verses compairing and conditionals in one operation which i feel dosn't allow as much freedom, but to everyone his own). Though, this is all based on old documentation.


The only problem with cmov* is that they do not exist in processors prior to Pentium Pro... Conditional assembly can be the solution here...

I ran into this problem when I tried to run the ReactOS livecd in a pentium MMX... The boot failed with an invalid opcode. When I run the live cd in bochs, I setup a breakpoint in that address and it was a conditional move.

Of course, if you are writing code to run in Long Mode, this isn't a problem...

Quote:
Quote:
pretty often


I seldom have small jumps, perhaps why i'm so against them. Though, i can't argue with anonymous labels for small jumps. I'm just sick of seeing them used for really big jumps, especially when mixed with named labels, some of which are in between the jump. Though, i purposely loose track of such ugly code.


When I started using anonymous labels, I had the habit of using them in large loops. However, latter I discovered that big, special purpose loops have no need to be labeled anonymously and that sometimes anonymous labels make them more confusing to read.
I don't use they much in large loops now, but I think they are still useful, specially to jump forward over some instructions, in IF-ELSE or IF-THEN-ELSE -like constructs.


PS: Please, *do* reread your posts and pass it through a spell checker before sending them... "anonymous" has only one "n", "labels" are not "lables", and "purposely" is not "purpously"... This is not a personal attack, but I'm tired of this kind of mistakes...

JJ
Post 04 Jul 2007, 20:56
View user's profile Send private message MSN Messenger Reply with quote
Jeronimus Linuxius



Joined: 28 Jun 2007
Posts: 37
Jeronimus Linuxius
kohlrak wrote:
Quote:
So do you really think that opening the find window and writing the label name makes it simpler to deal with local labels than with anonymous?


Yelp...


Nope!
Specially if you are in a GUI. And also not every GUI has to support shortcut keystrokes... For example, afaik menuetOS GUI doesn't support them in most apps.

Quote:
Quote:
Difficult because at some point you may need to express similar ideas in more than one label.


I've come accross this situation once for multiple window procs. For when i don't handle a message, i usually name a lable such as "go" or "notsupported." Though, i've found that in a situation like that, you could just add the name of the window or the proc for the window infront of the lable.


Namespace tricks are not absolute answers to the problem we are discussing because namespaces have limits.
Of course namespaces can help avoiding the problem to a great extend, but it still exists.

Quote:
Quote:
Of course, but if they enclose groups of statements in brackets (which don't have names), what's the problem if an asm programmer encloses groups of instructions in anonymous labels? That's just a matter of indentating the anonymous labels differently from normal code and from other labels.


The fact that brackets keep code together, anonymous labels have a tendency to sprawl themselves all out over a large distance of code.


They only "tend" if the programmer wants to...

Quote:
Quote:
Sometimes we need to alternately test for a different set of characters, and this can complicate things...


You can always set the base to the base of the string.


Correct if I'm wrong, but I think it was YOU who told that jumps flush the prefetch queue!...

Quote:
Quote:
Now, I don't understand what's your problem with anonymous labels. If you don't need them, that's your busyness, but I think their absence is a lack...


The fact that we still have to read it. You may be writing it, but we end up reading it.


Do you think I like to read C code plenty of #ifdefs?

What do you think about those who want to write code to fasm and have to look for free names every time they want to define a label, because the namespace is overfilled cause the code doesn't even use local labels?

Features can't be removed just because half a dozen of people think that they make it difficult to deal with the code.
Better having them used only be those who want them than removing and rendering them completely unusable.

Quote:
Quote:
i wouldn't agree here. For simple small jump-over-something, anonymous label looks better than if to me:


Small jumps usually aren't a major problem... But how often do we have small jumps?


We have them quite often... Think if you want to print something to the screen if a given condition is met...

JJ
Post 04 Jul 2007, 21:47
View user's profile Send private message MSN Messenger Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
I'm not an expert in CPU architecture, but as far as I know, branch predictors are there exactly to prevent this...


I was unaware that intel had such a system.

Quote:
a theory about whether they are likely to be followed or not is built by the prefetch queue, and the prefetch advances accordingly


That dosn't sound like a perfect system, but i'm guessing that it does work some times, which is better than no implimentation at all.

Quote:
The only problem with cmov* is that they do not exist in processors prior to Pentium Pro... Conditional assembly can be the solution here...


cmovxx, wouldn't that be comparing and doing things in one operation or am i thinking of another instruction..? What i'm talking about is more along the lines of this...

Code:
cmp eax, 0
movib [eaxwentzero], 0    


It would check if eax is below 0, then movs 0 into eaxwentzero boolean variable. Not an overly practical example, but it could handle the one liners easier.

Quote:
PS: Please, *do* reread your posts and pass it through a spell checker before sending them... "anonymous" has only one "n", "labels" are not "lables", and "purposely" is not "purpously"... This is not a personal attack, but I'm tired of this kind of mistakes...


Have one handy that's not bloated.

Quote:
Namespace tricks are not absolute answers to the problem we are discussing because namespaces have limits.
Of course namespaces can help avoiding the problem to a great extend, but it still exists.


Last time i checked you can have pretty large labels, so you can use a "namespace in a namespace trick." You'll end up using large names in large programs, but it'll be readable.

Quote:
They only "tend" if the programmer wants to...


Tendancies such as this *CAN* go un-noticed until it's too late, because they're more worried about what's in there, and sometimes copy and pasting the wrong thing can cause this problem. I don't know how many times i've accidentally copy and cut something from one location to another and not even know i accidentally included something extra.

Quote:
Correct if I'm wrong, but I think it was YOU who told that jumps flush the prefetch queue!...


Who said it had to be implimented through a jump. Let's say you want to test set alpha, you can set ebx to the value of alpha and incriment alpha as needed. Want to test set beta now, set ebx to beta and incriment and decrement as needed. If you're using conditional operations to decide weather or not to test beta set, there's no way you're going to get out of a jump anyway.

Quote:
What do you think about those who want to write code to fasm and have to look for free names every time they want to define a label, because the namespace is overfilled cause the code doesn't even use local labels?


I think they need to find a better namespace name.

Quote:
Features can't be removed just because half a dozen of people think that they make it difficult to deal with the code.
Better having them used only be those who want them than removing and rendering them completely unusable.


Fine, don't remove them and use them to your heart's desire. Don't expect everyone to be willing to read your code. Not a problem if you have no intention for people to do, but if you find that you need help, don't expect too much help if you abuse the feature. If some one has too much trouble reading your code, they won't bother trying to help you because it's too much work. Kindness goes only so far.

Quote:
We have them quite often... Think if you want to print something to the screen if a given condition is met...


Depending on what it is, you could just set the pointer(s) as needed, then do a jump to a common print section. Kind of like an exception handler. I do this alot to avoid constantly jumping over something when i don't want to print it, then you have less jumps actually being executed if you're trying to report an error. If you're not, then you're probably just jumping a 1 liner, which i don't mind with the fancy feature, but the longer the jump (and/or the more of them) the more annoying.


Last edited by kohlrak on 05 Jul 2007, 21:25; edited 1 time in total
Post 05 Jul 2007, 01:05
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
kohlrak wrote:

cmovxx, wouldn't that be comparing and doing things in one operation or am i thinking of another instruction..? What i'm talking about is more along the lines of this...

ffs, look up the instruction in the intel instruction manual...

While the CMOVxx instruction does get rid of branch prediction, it still imposes a dependency, so you should still try to do branchless solutions if you can.

kohlrak wrote:

Jeronimus Linuxius wrote:

PS: Please, *do* reread your posts and pass it through a spell checker before sending them... "anonymous" has only one "n", "labels" are not "lables", and "purposely" is not "purpously"... This is not a personal attack, but I'm tired of this kind of mistakes...

Have one handy that's not bloated.

The spell checker of firefox2 works pretty well and isn't too bad.

kohlrak wrote:

Jeronimus Linuxius wrote:

What do you think about those who want to write code to fasm and have to look for free names every time they want to define a label, because the namespace is overfilled cause the code doesn't even use local labels?

I think they need to find a better namespace name.

They need to use local labels... local labels are perfectly fine, and you'd be an idiot not to use them. Anonymous labels are still another issue though, imho.


Last edited by f0dder on 05 Jul 2007, 09:57; edited 1 time in total
Post 05 Jul 2007, 08:55
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid
Also note that CMOVcc r32, r32 in 64bit mode clears upper 32 bits of destination operand even if condition is false Wink
Post 05 Jul 2007, 09:52
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
While the CMOVxx instruction does get rid of branch prediction, it still imposes a dependency, so you should still try to do branchless solutions if you can.


I have a pentium 4, so i'm assuming that i can't use it anyway... Though i think people could benefit from more than just a mov that's like that.

Quote:
The spell checker of firefox2 works pretty well and isn't too bad.


Last time i tried firefox, it didn't work for some unknown reson. Firewall wasn't blocking it, but for some reson it didn't work. Anyone have a stand alone solution?

Quote:
Also note that CMOVcc r32, r32 in 64bit mode clears upper 32 bits of destination operand even if condition is false


Oh fun...

Quote:
They need to use local labels... local labels are perfectly fine, and you'd be an idiot not to use them.


I personally don't bother with local lables, but then again, i've never had trouble with not having enough names either.
Post 05 Jul 2007, 11:26
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
kohlrak wrote:

While the CMOVxx instruction does get rid of branch prediction, it still imposes a dependency, so you should still try to do branchless solutions if you can.
f0dder wrote:


I have a pentium 4, so i'm assuming that i can't use it anyway... Though i think people could benefit from more than just a mov that's like that.

CMOV was introduced in the PPRO... PPRO was the cpu introduced between the pentium and the pentium-II. In other words, it's age old, and you can use it on your P4.


kohlrak wrote:

vid wrote:

Also note that CMOVcc r32, r32 in 64bit mode clears upper 32 bits of destination operand even if condition is false

Oh fun...

X86-64 is such a hack Smile

kohlrak wrote:

f0dder wrote:

They need to use local labels... local labels are perfectly fine, and you'd be an idiot not to use them.

I personally don't bother with local lables, but then again, i've never had trouble with not having enough names either.

If you have, say, a bunch of color-conversion routines for different source and dest formats, which is cleaner? Label names like cnvRGB888_RGB565_scanloop:, or simply .scanloop: inside your cnvXXX_XXX functions?
Post 05 Jul 2007, 11:34
View user's profile Send private message Visit poster's website Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
CMOV was introduced in the PPRO... PPRO was the cpu introduced between the pentium and the pentium-II. In other words, it's age old, and you can use it on your P4.


And i missed that...? Oh there it is... can't believe i missed that... lol

Quote:
X86-64 is such a hack


Not surprised... XD

Quote:
If you have, say, a bunch of color-conversion routines for different source and dest formats, which is cleaner? Label names like cnvRGB888_RGB565_scanloop:, or simply .scanloop: inside your cnvXXX_XXX functions?


The latter. But i would use locals if i had the need for them, but i don't outside of procs for windows, but i let the proc macro handle them for me. I see local variables incredibly useful when the need arouses.
Post 05 Jul 2007, 11:42
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3  Next

< Last Thread | Next Thread >
Forum Rules:
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 vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.