This is an archived, read-only copy of the United-TI subforum , including posts and topic from May 2003 to April 2012. If you would like to discuss any of the topics in this forum, you can visit Cemetech's z80 & ez80 Assembly subforum. Some of these topics may also be directly-linked to active Cemetech topics. If you are a Cemetech member with a linked United-TI account, you can link United-TI topics here with your current Cemetech topics.

This forum is locked: you cannot post, reply to, or edit topics. Z80 & 68k Assembly => z80 & ez80 Assembly
Author Message
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 11 Dec 2011 11:05:29 am    Post subject:

No problem XD Actually, in the next three days I have 4 exams and then I may or may not be without internet until mid January. :/ Good luck!
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 26 Dec 2011 05:00:51 pm    Post subject:

Hello everyone and merry Christmas!
I finally got some precious time for my asm study.

Im stuck on floating point numbers. Its in lesson 15, under "Constant division".
I pretty shure that an explanation in other words will help.
Back to top
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 29 Dec 2011 12:52:51 am    Post subject:

I personally didn't bother with that section and I've never needed to use it. I always stick with fixed-point or integer math, anyways.

EDIT: Sorry, I didn't actually answer anything. I really couldn't follow it as it is.


Last edited by Guest on 29 Dec 2011 12:55:39 am; edited 1 time in total
Back to top
asdf


Advanced Newbie


Joined: 17 Aug 2008
Posts: 73

Posted: 30 Dec 2011 12:39:31 pm    Post subject:

I've never bothered with floating point numbers either as i've never really had a use for them. Actually, i just checked that section out and don't really understand it either. I'm not very good at math, though. I'll reread through the section above about fixed-point arithmetic and see if i can help out any. What in particular is it that you need help with?
Back to top
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 30 Dec 2011 07:28:32 pm    Post subject:

I usually only ever understand something after I have had to go through and figure it out myself :/ Unfortunately, I have found fixed-point math to be very useful and typically faster, so I haven't had much need to work with floating point.
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 02 Jan 2012 06:20:19 pm    Post subject:

Sorry i totally forgot about this topic Smile. I think i figured it out few days ago, now im at the VAT.
There are few things that sound strange. Here is how i understood it:

OP registers are to hold fixed point numbers.
But you can also use them to make a variable by loading some tokens into it:

Code:

LD HL, Variable
bcall(_mov9toOP1)
bcall(_createReal)  ;creating the variable named X

Variable:
.DB RealObj ,tX ,00h, 00h ;i hope that whats after this doesnt matter for creating a variable. otherwise 5 more nulls.

Now what i think it does is it creates the variable by loding the name to the VAT.

If what i said is correct then how do i load a number to a variable?

PS. One more thing.
Does $80, $77, $75, $16, $99, $60, $94, $17, $87 equal to -7.5169960941787 × 10^-7?? Because i think its 10^-8
Back to top
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 03 Jan 2012 05:02:54 pm    Post subject:

jammasterz wrote:

Sorry i totally forgot about this topic Smile. I think i figured it out few days ago, now im at the VAT.
There are few things that sound strange. Here is how i understood it:

OP registers are to hold fixed point numbers.
But you can also use them to make a variable by loading some tokens into it:

Code:

LD HL, Variable
bcall(_mov9toOP1)
bcall(_createReal)  ;creating the variable named X

Variable:
.DB RealObj ,tX ,00h, 00h ;i hope that whats after this doesnt matter for creating a variable. otherwise 5 more nulls.

Now what i think it does is it creates the variable by loding the name to the VAT.

If what i said is correct then how do i load a number to a variable?

PS. One more thing.
Does $80, $77, $75, $16, $99, $60, $94, $17, $87 equal to -7.5169960941787 × 10^-7?? Because i think its 10^-8

You are definitely getting it and I have a few notes to add or amend:
-OP registers hold floating point numbers (floating point means the decimal is somewhere in the number, fixed point means that the decimal is in a specific, pre determined way).
-OP registers can also hold the names of variables.
-You can substitute bcall(_mov9toOP1) with rst rMov9ToOP1 which is 2 bytes smaller and a lot faster
-Your code should work just fine and the name is correct. What is after does not matter
-When the OS creates a variable, a bunch of things are done. Memory is allotted for the variable, then there is something like 24 addresses that need to be updated, then the VAT has some info added such as the var name, type, and address.

(I think it is 24 address, give or take a few).

EDIT: Also, the number above is actually *10-9 because 77h-80h=-9


Last edited by Guest on 03 Jan 2012 05:05:46 pm; edited 1 time in total
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 06 Jan 2012 07:04:59 am    Post subject:

Yeah sorry, i knew it was floating point, just a little mistake here. As allways all my questions answered, thank you!

I've been reading a little and now im at interrupts. Again there are some pretty strange things, that are hard to understand.

1.(Its actually Low-Level Key Input) If you want to get a keypress using OUT and IN, you have to first
1. Output group you want to read to port #1.
2. Get input(after 4 cycles i think).
But now, if i want to get any keypress like _GetKey does, how do i differ the keys if i dont know which group to send? For example if i press [Trace] it could be [Trace],[->], [1],[2],[3],[+] and .

2.Interrupts.

1.I register holds 8 upper bytes of the adress. Bit 7 and 6 seem to be random(really?), and the rest is allways %111111. Because those 2 bits are random you must ensure that whatever they are, the mashine jumps to the right ISR:

Code:

LD HL, $9DF0 ;adress of the ISR

LD (993F), HL
LD (997F), HL
LD (99BF), HL
LD (99FF), HL  ;because of the 2 random bits there are 4 possibilities where the mashine can jump.

2."Interrupts should execute as fast as possible. If an interrupt takes too long to complete it may very well be reinitiated and loop forever. To make sure it doesn't happen you must output 0 to port 3, to disable the hardware like: [ON] key interrupts, Timer and Linkport."- Why can this happen?

3. According to what i read you don't know when an interrupt is triggered. Thats why you must disable them to load the required data and then enable them again.

Code:

DI
LD HL, interrupt
LD ($993F), HL
LD ($997F), HL
LD ($99BF), HL
LD ($99FF), HL

LD A, $99
LD I, A ;loading the needed data with interrupts off

LD A, %00001101  ;enabling hardware before the interrupts are On.
IM 2
EI  ;As far as i know interrupts start triggering "randomly"(or with a certain interval) from this moment.


Why is he turning the hardware on if he said not to?

Wow thats a lot of questions Very Happy. I hope it doesnt bother anyone. Thank you again for helping!
Back to top
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 07 Jan 2012 11:44:08 am    Post subject:

Okay, here are some answers and some more info that I had to learn myself way back when...

For reading the keyport, the key groups are pretty simple to obtain. if you look at the binary, the first group is %11111101. the second group is %11111011, third is %11110111, et cetera. However, the group 7Fh does not exist (there are only 7 key groups. Keys also follow the same pattern, so if you want to make keytesting programs, you will get familiar with shifting, rotating, and cpl. CPL is a neat instruction that inverts the bits of A. So what are the inverted bits of the keygroups? 2,4,8,16... This is a lot simpler to remember to pass an argument through Ans to a program than 254,252,248...

So anyways, if you wanted to make a program that tested a key group and spit out the result for TI-BASIC users:

Code:

     bcall(_RclAns)
     ld a,-1
     out (1),a
     bcall(_ConvOP1)    ;makes for a heck of a delay XD
     cpl
     out (1),a
     ld hl,0            ;takes 7, unwasted cycles, 3 wasted (l is set later)
     in a,(1)
     cpl                ;to get an easy to read result
     ld l,a
     bcall(_SetXXXXOP2)
     bcall(_OP2ToOP1)
     bcall(_StoAns)
     ret

Another trick I don't believe you are taught in that tutorial is that you can reset multiple bits to read multiple key groups. So to codes I use to wait until people have pressed any key or stopped:

Code:

;Wait until no keys are pressed (good for when a user has to press a key before and might be slow to release)
     xor a         ;an optimised way to do ld a,0. 3 cycles faster, 1 byte smaller. Also sets z, resets c.
     out (1),a
     in (a),a      ;why use delays when you are testing all the keys?
     inc a         ;FF if no keys gets incremented to 0, so z flag tells if a key is pressed
     jr nz,$-6
;Wait until a key is pressed. Pretty much, change the jr nz to jr z. You can also change it to $-5...
     xor a         ;an optimised way to do ld a,0. 3 cycles faster, 1 byte smaller. Also sets z, resets c.
     out (1),a
     in (a),a      ;why use delays when you are testing all the keys?
     inc a         ;FF if no keys gets incremented to 0, so z flag tells if a key is pressed
     jr z,$-5      ;A is 0, why reset it again?

So now here is the code I am sure you would prefer: GetKey. This is a routine that I have spent time optmising (and I know it can still be better optmised). That means it might be difficult to follow in places, but I think it is rather nice Smile A few sections of code serve multiple purposes and currently only 1 byte is wasted. This is designed to work in 6MHz and 15MHz:

Code:

GetKey:
;     A and BC contain the keypress
          ld bc,0             ;just to initialise
          ld de,$7FFF         ;D is the key group, E is a counter at -1
KeyLoop:                      ;**note: key group 7Fh is null
            rlc d             ;we rotate the key group to get the next
            ld a,d            ;we load the key group in A
            out (1),a         ;Output it to port 1
            inc e             ;increment the counter, 4 cycles
            sub 7Fh           ;3 purposes
                              ;If the key group is back at 7Fh, this will be 0 and we can quit
                              ;in otherwords, the z flag will be set
                              ;and A is 0 as is BC meaning no key was pressed
                              ;Also, 7 cycle delay
            ret z             ;5 cycle delay (if it does RET, it is 11, but then the delay does not matter)
            nop               ;need 4 cycles more if the calc is at 15MHz
            in a,(1)          ;Get the key values
            inc a             ;FF means no keys in that group.
                              ;Add 1 and you get zero... z flag is set
            jr z,KeyLoop      ;if no keys in that group, jump back
            dec a             ;there was a keypress, so set it back
              inc c           ;C was 0, this will count to the next key
              rra             ;rotates a until it hits a reset bit
                              ;reset means the key was pressed
              jr c,$-2        ;jump back two bytes
            ld a,e            ;A is now the first counter. Needs to be multiplied by 8
            rlca              ;multiply by two since the last bits are reset
            add a,a           ;multiply by two, properly
            rra               ;multiply by 2 since the c flag is not set
            add a,c           ;add the other counter
            ld c,a            ;so that BC can contain the value, too
            ret               ;

I gave 3 ways to multiply by 2, but the rotates are not always reliable. if the last bit in A might be set, rlca will not work. If the C flag is set, rra will not work. ADD A,A is the actual way to do it. Also, some tips you may someday use long down the road that you did not ask for: :P

XOR A is a fast way to set A to 0. It is 4 cycles and 1 byte-- ld a,0 is 7 cycles and 2 bytes
OR A is a fast way to check if A is 0. It is 4 cycles and 1 byte. cp 0 is 7 cycles and two bytes. Also used as a way to reset the c flag.
AND A is the same thing as OR A.
CP A is the same thing as OR A.
ADC A,A will do the same thing as RLA. Same size and speed.
SUB A is like XOR A, but it also sets the half carry flag (only used by one instruction: DAA)
SBC A,A can be useful. If the c flag is set, this will just make A FFh. If the c flag is reset, this will make A zero and set the z flag.
ADD A,A is half the size and speed of SLA A and is the same thing.
Sign flags check the last bit. If you want to jump or RET, use M or P (minus or plus). I did not find it useful with GetKey, but I thought it might since shifting to 7Fh would mean I could do RET P.

You seem like you are going to be really good with assembly, so learning these tricks early might prove really useful to you.

Now, next topic, interrupts:

Well, I don't know what he was testing, but in my experience, the lower bits are random and that has been confirmed by other Z80 coders. Anyways, here are some details:

The interrupts that we can use will execute about once every 1/140th of a second. If your interrupt takes more time than that, your interrupt could fire again inside itself creating an infinite loop. Interrupts are not my strongpoint in any way and I find them tricky to work with. Because of this, I have never gotten the full use out of my interrupts. Here is an interrupt outline that I have gotten to work before and I am using with Grammer:

Code:

interrupt:
     exx \ ex af,af'
;<<code goes here>>
     jp 3Ah
interrupt_end:


I have been coding in assmebly for a while, but I never learned interrupts well enough. I am working on it now because folks seem to like grayscale nowadays .__.

Also, I am not sure why hardware interrupts are toyed with in that code.
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 07 Jan 2012 05:36:59 pm    Post subject:

ThunderBolt wrote:

Okay, here are some answers and some more info that I had to learn myself way back when...

For reading the keyport, the key groups are pretty simple to obtain. if you look at the binary, the first group is %11111101. the second group is %11111011, third is %11110111, et cetera.


Isn't the first group %11111110(FE)?


Code:

     bcall(_RclAns)  ;??
     ld a,-1    ;-1? FF?
     out (1),a    ;output ff to 1- i think you ment FE(-2)
     bcall(_ConvOP1)    ;makes for a heck of a delay XD
     cpl  ;inverts a. a=0 or in case A having FE a=1
     out (1),a  ;output 1
     ld hl,0            ;another delay
     in a,(1)   ;get answer, i have no idea what this is after sending first FF and then 0
     cpl                ;invert result
     ld l,a
     bcall(_SetXXXXOP2) ;i dont know what this is but i guess its conversion of HL into FP
     bcall(_OP2ToOP1)
     bcall(_StoAns)
     ret

One litttle question- is there some sort of mnemonic compendium other than INC file that explains functions of the routines like _RclAns?
Back to top
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 07 Jan 2012 09:02:31 pm    Post subject:

jammasterz wrote:

Isn't the first group %11111110(FE)?

Oops, yes, sorry Smile
jammasterz wrote:

One litttle question- is there some sort of mnemonic compendium other than INC file that explains functions of the routines like _RclAns?

On TI's website, you can download the SDK and there is a PDF that will detail a good number of bcalls. I would suggest downloading that for times when you are without internet, but if you have internet, I recommend going here. It has lots of information detailing documented and otherwise undocumented bcalls and RAM addresses.
Back to top
asdf


Advanced Newbie


Joined: 17 Aug 2008
Posts: 73

Posted: 08 Jan 2012 10:23:35 am    Post subject:

Alright, so i started writing this last night but didn't finish. It looks like your questions were already answered, but just in case:
jammasterz wrote:

1.(Its actually Low-Level Key Input) If you want to get a keypress using OUT and IN, you have to first
1. Output group you want to read to port #1.
2. Get input(after 4 cycles i think).
But now, if i want to get any keypress like _GetKey does, how do i differ the keys if i dont know which group to send? For example if i press [Trace] it could be [Trace],[->], [1],[2],[3],[+] and .

I'm not sure if i understand your question, basically what you do is output the group you want to read keys from. So, if you want to check for [2nd], send Group7 ($BF) to port 1. That way, it will only read keys from that group. If a key from another group or no key is pressed, it'll return $FF. You can also AND two or more groups to read from more than one group at a time, but then you'll have the issue you mentioned above. Usually it's not a problem though. Another way to do it is to check keys from one group, reset the key port (output $FF), then check the next group you want to read keys from.

Quote:
2.Interrupts.
1.I register holds 8 upper bytes of the adress. Bit 7 and 6 seem to be random(really?), and the rest is allways %111111. Because those 2 bits are random you must ensure that whatever they are, the mashine jumps to the right ISR:

Why is he turning the hardware on if he said not to?

Wow thats a lot of questions Very Happy. I hope it doesnt bother anyone. Thank you again for helping!

First, you may be interested in the interrupts guide:
http://www.ticalc.org/pub/text/z80/intguide.txt
Alright, so by turning the hardware on do you mean the ei? Without the ei, your interrupt won't run. What happens is instead of running the default TI interrupt (im 1) it now goes to the interrupt pointed at by i+a random byte. What you normally do then is find a place in saferam (such as $9900) where you can load 256 bytes ($FF+1 bytes) and fill that entire space with one byte (for example $9A). So $9900-$9A00 will be filled with $9A. When the interrupt is called, it'll pick a random byte between $9900 and $99FF (because i=$99) and will read two bytes. So the interrupt will jump to $9A9A, which is where you'll need to have your interrupt stored or at least a jp to your interrupt in your program.

The part about making the interrupt quick, if your interrupt takes too long the next interrupt could get called before it finishes and you would be stuck in an infinite loop. You could also disable interrupts when entering your routine and reenable them upon exiting, though generally you want your interrupt to be short and sweet.
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 08 Jan 2012 12:32:04 pm    Post subject:

asdf wrote:

If a key from another group or no key is pressed, it'll return $FF.
You can also AND two or more groups to read from more than one group at a time, but then you'll have the issue you mentioned above. Usually it's not a problem though. Another way to do it is to check keys from one group, reset the key port (output $FF), then check the next group you want to read keys from.

You just answered on 2 of my major questions Smile Thank you.
One more thing- For example if i send group $FE to port 1 and then press a button from group FD, i get $FF as an answer. And now i want to check which key was that, im SHL the previous group i've sent (FE >> FD) and send it again. Now do i have to press that key again or is the pressed key stored until it has been read?
Back to top
asdf


Advanced Newbie


Joined: 17 Aug 2008
Posts: 73

Posted: 08 Jan 2012 03:36:56 pm    Post subject:

Ok, so when you are using direct input, it is a lot faster than using any TI-BASIC commands/_getkey/_getcsc. Usually, you will have a loop which will test for your key input. Say we want to use 2nd to confirm, Alpha to cancel, and the arrow keys to move. First check if 2nd or Alpha has been pressed.

Code:
    ld a,$BF        ;group 7, 2nd
    out (1),a
    in a,(1)
    bit 5,a         ;2nd
    jr z,confirm
    bit 6,a         ;alpha
    jr z,cancel
Now, check the arrow keys:

Code:
    ld a,$FF
    out (1),a        ;clear the key port
    ld a,$FE        ;group 1, arrow keys
    out (1),a
    in a,(1)
    rra
    jr nc,down
    rra
    jr nc,left
    rra
    jr nc,right
    rra
    jr nc,up
    jr loop
Btw, look at the values for down (%11111110), left (%1111101), right (%11111011), and up (%11110111). Using rra, you can tell which key is being pressed by the location of the 0 (aka, when rra returns nc, no carry).

Chances are, if you are holding left while the program is running through the section that tests for 2nd and Alpha, chances are you will also be holding left when the program tests for left. The time it takes to run through each loop is very small, so don't worry about missing a keypress.
Back to top
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 08 Jan 2012 08:07:57 pm    Post subject:

To give you an idea of just how fast direct input is, using the code above (which can be optimised >.>) it will take less than 200 cycles to run. What does that mean? In the slowest mode (6MHz), that code will loop 30 000 (thirty thousand) times a second. So pretty much, it is highly unlikely that the user will be able to press and release a key that fast. The code I gave to test which key is being pressed will take at most 746 cycles (that would be the [del] key, by the way) and that means it executes at over 8000 times per second. The OS uses timers and a counter as a key debouncer (I was actually the person to document the location and specifics of the debouncer on WikiTI).

Last edited by Guest on 08 Jan 2012 08:08:34 pm; edited 1 time in total
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 09 Jan 2012 10:37:56 am    Post subject:

Okay, so i finally found some time to read everything you said, but i still find it difficult with the out in instructions.

In the tutorial im reading the author said:
-You send the group you want to read from to port 1.
-Wait for 8 cycles(maybe less, but he said 2 NOPs)
-Read the keycode from the port 1.

I've done some tests and i found out that the delay is not needed.

Code:

Readkey:
    LD A, %11111101
    OUT (1), A ;note no delay between in and out
    IN A, (1)
    CP %11111011
    JP Z, minus
     
    LD A, %11111110
    OUT (1), A  ;same here, no delay
    IN A, (1)
    CP %11110111
    JP Z, up
   
    JP Readkey
minus:
    LD HL, vminus
    bcall(_PutS)
    RET
up:
    LD HL, vup
    bcall(_PutS)
    RET
vminus: .DB "Minus!", 0
vup: .DB "UP!", 0   

This code runs just fine.

Here is another oddd thing in asdf's code:


Code:

    ld a,$BF        ;group 7, 2nd
    out (1),a
    in a,(1)
    bit 5,a         ;2nd
    jr z,confirm
    bit 6,a         ;alpha
    jr z,cancel

If alpha is in group DF, why is he looking for it in group BF?
Back to top
Xeda112358


Active Member


Joined: 19 May 2009
Posts: 520

Posted: 09 Jan 2012 11:05:36 am    Post subject:

It depends on the situation for the delays and also the calculator. I have found programs to "glitch" and then I found out that it was because I had not enough delay. For example, you might notice that Enter registers as a Down keypress or vice-versa without a delay.

As for the code from asdf, I think it was a mistake. It should be DFh.

As for in and out, I had trouble with it for a long time. I learned it in hexadecimal and it was a lot easier. D301 would write to the port and DB01 would read from the port. Eventually I found a way to remember the syntax:

out will OUTput to the port. since ld a,b stores b to a, out stores a register to a port. So, out (),a.
in will get INput from a port. Since we are storing from a port, the port argument is last.
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 10 Jan 2012 03:34:32 am    Post subject:

So i've been playing aroun a little with nterrupts and i wrote this code. Of course it doesnt work, and i cant find the error.
I could only see that the calc stops on HALT which means interrupts stop triggering after running my code.

Code:

.org    $9D93
.db    t2ByteTok, tAsmCmp
    LD HL, interrupt
    LD DE, $9872
    LD BC, interrupt_end + 4 - interrupt  ;i want the message to be copied too
    LDIR

    LD HL, $9872
    LD ($993F), HL
    LD ($997F), HL
    LD ($99BF), HL
    LD ($99FF), HL

    DI
    EX AF, AF'
    EXX
    LD A, $99
    LD I, A
    IM 2
    EI
    RET

interrupt:
    LD A, $FF
    OUT (1), A

    LD A, $FD
    OUT (1), A
    NOP
    NOP
    IN A, (1)
    BIT 7, A
    JP NZ, $003A

    LD HL, msg - $9D95 + 4 + $9872
    bcall(_PutS)
    JP $003A
interrupt_end:

msg: .DB "HEY", 0


Last edited by Guest on 10 Jan 2012 05:57:29 am; edited 1 time in total
Back to top
asdf


Advanced Newbie


Joined: 17 Aug 2008
Posts: 73

Posted: 10 Jan 2012 04:22:40 am    Post subject:

Yeah, that was a mistake on my part, sorry. I'll look through the code later, but generally you set up a 256-byte table, i'm not sure if what they say in 28 Days about just the two upper bits being random is true or not. Also, the value in HL that you are loading doesn't really point anywhere (it points to your string). Try loading $9872 into hl first.

Again, i'll look through it more thoroughly later, if ThunderBolt or someone else doesn't beat me to it Smile
Back to top
jammasterz


Advanced Newbie


Joined: 28 Nov 2011
Posts: 72

Posted: 10 Jan 2012 04:34:35 am    Post subject:

I corrected it, but the problem persists.

EDIT: Besides that i jut noticed a problem with message- the adress has to be changed. BTW, i do not want to switch back to mode 1.
Even whn the program ends the calc has to display hey when i press enter.


Last edited by Guest on 10 Jan 2012 05:50:00 am; edited 1 time in total
Back to top
Display posts from previous:   
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
    » Goto page Previous  1, 2, 3, 4  Next
» View previous topic :: View next topic  
Page 2 of 4 » All times are UTC - 5 Hours

 

Advertisement