Parallax Forums
  HomeLog InRegisterCommunity CalendarSearch the ForumHelp
   
Parallax Forums > Public Forums > Propeller Chip > ZiCog a Zilog Z80 emulator in 1 Cog  Forum Quick Jump
 
New Topic Post Reply Printable Version
1085 posts in this thread.
Viewing Page :
 
[ << Previous Thread | Next Thread >> ] | Show Newest Post First ]

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/27/2009 4:50 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
ZiCog a Z80 emulator for the Propeller.

Run CP/M 2 and 3, Microsoft BASIC etc on a Propeller.

Latest version is zicog_v0.10.zip

--------------------------------------------------------------------------------------------------------------------

The demise of the 4 COG Z80 emulator project was precipitated by the realization that it is possible to create a full up Z80 emulator that uses only one COG. Further that this emulator would be just as fast as the 4 COG effort, would be a lot more elegant and understandable than the old PropAltair 8080 emulator and would be far more friendly to external RAM.

How is this possible?

The classic way of building an emulator is to have a look up table that is used to get from a given instruction opcode to the function that will emulate that instruction. This is fine if you have a lot of space to put those instruction handler functions. In the Prop COGs there is not enough space. We could try to use more COGs. This is slow and wasteful of COGs.

Another emulator approach is to try and decode the various bit fields of the opcode and determine what the instructions data sources and destinations are and what operations should occur. In this way one can fold up the emulator into a twisted mess of code logic that will fit in a COG. This was how the first PropAltair 8080 emulator worked. It is slow.

A new approach: After looking at the emulation process long enough I came to the realization that most of the instructions boil down to three steps:
1) Get an operand from somewhere. The Source.
2) Do some operation with that operand and (mostly) the accumulator (The A register). The Operation.
3) Put the result somewhere. The Destination.

In the 8080 there are about 25 different sources and destinations: Registers A, B, C etc, memory via HL, memory via direct address, immediate data etc etc. There are about 30 different operations, ADD, SUB, ROT, INC, DEC etc etc.

All these sources, destinations and operations can be implemented in a from 2 to 20 lines of PASM each and they will all easily fit in a COG. All we need now is a way to connect different combinations of source, operation, destination together to implement each instruction.

This is where Cluso comes in. Who should, from now on, be referred to as "The Great Cluso".

Clusso suggests that one can put three COG addresses, vectors, in each LONG of a look up table, plus 5 bits of other possibly useful info. For a long time I wondered what such a clever thing could be used for. Until the euro dropped.

The first vector jumps us to a procedure to fetch the source info. The second vector gets us to some code to perform the operation and third vector takes care of posting the result to the right destination. This technique can also be used to take care of conditional/unconditional jumps, calls and returns.

Using this approach it is possible to fit a whole 8080 emulator in one COG with no LMM or other such junk and around 90 longs free!!

Turning to the Z80 we see that it has more than twice as many opcodes as the 8080 BUT looking closely we see there are only a handful more of those Source, Destination and Operation functions. Which can be coded as PASM in the free longs we have. The logic that ties them all together is in the dispatch tables in HUB.

Enough of the long lecture. My first pass at this idea is attached. I have not included the rest of the emulator files as this barely runs as it is but it does show the general outline. There is code in place for 90% of a Z80.

Early tests show that speed is nearly up to that of the 4 COG version, faster than the old PropAltair version and can be pushed a little more with some tweaks here and there.

It is early days yet but this file is intended to show what is coming for those who want to put CP/M on a Prop with external RAM or build some other emulator.


For me, the past is not over yet.

Post Edited (heater) : 8/19/2009 4:44:49 AM GMT



File Attachment :
z80_emu.spin   124KB (application/octet-stream)
This file has been downloaded 523 time(s).

File Attachment :
zicog_v0_10.zip   114KB (application/x-zip-compressed)
This file has been downloaded 343 time(s).
Back to Top
 

TreeLab
Registered Member

Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Nov 2006
Total Posts : 136
 
   Posted 2/27/2009 7:34 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
@Heater (and The Great Cluso) : Bravo, this is very clever. I especially like the heartbeat ...
Can you give an estimate of the speed relative to a 4MHz Z80?

Cheers!
Paul Rowntree
Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/27/2009 8:02 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
Hmm... not so sure about actual Z80s. But an original Altair 8080 was running at about 350 thousand instructions per second (KIPS).

This code has had only minimal testing so far but a loop of INR A, OUT 0, JMP 0000 runs at 384KIPS which happens to be the same as the 4 COG version and faster than the old PropAltair version of 348KIPS. I know I can push this to 400KIPS with a few tweaks. like putting some or all of the registers into COG space. I will probably not do that though, it complicates the code and makes the break, single step and trace debug features messier.

Bear in mind that this may slow down when we start using external RAM so pushing too hard for little optimizations won't make much sense.

That heartbeat is what I use to measure the speed using the FrequencyCounter object.


For me, the past is not over yet.

Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/27/2009 8:12 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
"z80_emu" is a very boring name and there is already such a project on the net. Should I call "PropZ80" or something? What about "ZiCog" ?


For me, the past is not over yet.

Back to Top
 

Cluso99
We live onboard



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Apr 2008
Total Posts : 4114
 
   Posted 2/27/2009 8:20 PM (GMT -7)    Quote This PostAlert An Admin About This Post.

Heater:

It's a shame the 4 cog version didn't provide the gains you expected. Nice to see you are continuing the 1 cog version. Pleased to see the multiple vector approach is working (used this method in my undebugged spin interpreter to great effect).

If you are not already using a 6.0MHz xtal, this will give you an instant 20%.

Hopefully, my TriBladeProp will be away to manufacture over the weekend - you will be surprised at the extras I've done (no time to explain till it is away). Just taking a break.

Keep up the excellent work cool 

Postedit: PropZ80 sounds better - ZiCog is great but no-one will realise what it is.


Links to other interesting threads:
Back to Top
 

kwinn
Registered Member

Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Sep 2008
Total Posts : 1616
 
   Posted 2/27/2009 8:28 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
Wow. That is one of the most impressive pieces of code an data structuring I have seen. I think both of you deserve "The great" accolade. I am truly impressed by the structure and elegance of it.
As for the name, I like ZiCog. Somehow it seems to be in harmony with the "Propeller" spirit and way of doing things.
Back to Top
 

Mike Huselton
QuantumMax



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Nov 2007
Total Posts : 716
 
   Posted 2/27/2009 8:28 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
Pemu.


JMH

Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/27/2009 8:50 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
kwinn: Thank you. I think that's what they call "data driven programming" or at least "table driven"

Anyway it should be in every "Software Engineering 101" course to identify your primitive operations first and then design the code to use them.

It is fortuitous that the 8080/Z80 fits this scheme so well. We only have three vectors to play with in each table entry. With the 8080 you can get away with just "source", "operation" and "destination". As most operations work on the Accumulator (The A register) e.g. "ADD A, B" it does not need to specified in the table. Operations like "INR D" can work on any register/memory location, but here we only have one source and dest and they are always the same place.

Had the 8080 been like some CPU architectures and have two sources and a destination like "ADD dest, src1, src2" we would be out of luck.

James: "Pnut-Emu" What the..?


For me, the past is not over yet.

Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/27/2009 8:51 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
Ah "Pemu" that sound better :)


For me, the past is not over yet.

Back to Top
 

Mike Huselton
QuantumMax



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Nov 2007
Total Posts : 716
 
   Posted 2/27/2009 10:06 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
Glenlivet provided the inspiration...


JMH

Back to Top
 

Dr_Acula
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Dec 2008
Total Posts : 1640
 
   Posted 2/27/2009 10:38 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
What an awesome bit of code! For the rest of us - to quote Wayne's World, "we are not worthy"

I was kind of hoping since we hadn't heard from you for a bit that you were deep in the world of coding. The new code is very elegant. Re the Z80 specific instructions, if you can do just LDIR I reckon it could do the N8VEM. How would the 64k memory interface (and could it use the cluso triblade?)
Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/28/2009 2:13 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Dr_A: Na, it was nothing. Actually it is nothing, I would reserve the adjective "awesome" for the Linux kernel and such like.

I have been deep in the world of getting myself work with a new start up, so my Propelling may have to slow down somewhat soon.

LDIR, no problem I hope.

For sure half the motivation for this "yet another total rewrite" is to accommodate external RAM interfaces. The old PropAltair version was squeezed to the limit making it hard to find room in the COG for external RAM interface code. The four COG version made the space available but at the cost of speed and COGs and HUB RAM. Not to mention the hassle of ensuring that only one COG access the RAM at a time.

Cluso's TriBlade is the primary target platform just now and probably has the easiest requirements for adding external RAM driving code. Can't wait to get my hands on one.

Mike Green has a serial RAM chip solution that while slower would be amazingly quick and simple to construct hardware wise. That kind of serial access requires more COG code to shift the bits but will now fit I hope.

Leon has/had a board underway using an external RAM and a CPLD.

@Mike and Leon: How are those RAM solutions going ?


For me, the past is not over yet.

Back to Top
 

Cluso99
We live onboard



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Apr 2008
Total Posts : 4114
 
   Posted 2/28/2009 3:38 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Heater teasing... The TriBladeProp can handle a pair of 512Kx8 (or pair of 2Mx8 if you can afford them) plus (not either/or) microSD plus 24C256/512/1024 plus SPI Flash 1-64Mbit on Blade #2. It has one onboard PropPlug. Almost complete - just adding some tracks and links for options - then to pour the ground and power planes :-)


Links to other interesting threads:
Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/28/2009 4:00 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Good grief. Consider me teased :)

I'm sure CP/M with banked switched memory can't handle that much RAM.


For me, the past is not over yet.

Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/28/2009 4:08 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
I'm discovering things about the z80 that I'm not going to like.

E.G. There is "RLCA" which rotates the accumulator setting only the carry flag like an 8080. Then there is RLC A which sets zero, sign, parity and carry!!!

Things are going to get tight around here.


For me, the past is not over yet.

Back to Top
 

Dr_Acula
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Dec 2008
Total Posts : 1640
 
   Posted 2/28/2009 4:11 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
LDIR in 8080 code.

PUSH PSW
LDIR_LOOP:
MOV A,M
STAX D
INX D
INX H
DCR C
JNZ LDIR_LOOP
DCR B
JNZ LDIR_LOOP
POP PSW
RET

That is fun - LDIR calls a list of 8080 instructions which calls a list of prop asm instructions. This would work though maybe there are some optimisations. LDIR is very useful for block moves eg getting a block of memory out of an eprom and into ram.

Cluso, 512k eh? And all those mass storage options? Might have to look at rewriting some CP/M mass storage code. Keep it simple - if I sent you a number 0 to 1million can you send me a byte at that address? If yes (and I'm sure you can but I'm not an expert in how a prop might get a byte from a microSD), then CP/M can do the track-sector-to-address calculation. Then the microSD can become a disk drive within CP/M.

CP/M only needs 64k. The rest could be useful for the prop but CP/M doesn't need it. Do smaller ram chips fit on the triblade?

Post Edited (Dr_Acula (James Moxham)) : 2/28/2009 11:20:29 AM GMT

Back to Top
 

Cluso99
We live onboard



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Apr 2008
Total Posts : 4114
 
   Posted 2/28/2009 4:43 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Dr_A: Yes you can fit 128Kx8's but there is little price difference. The 512Kx8 are about $3. Only fit one. I was thinking the rest can be a RAM Floppy CP/M drive. Only one of the RAMs has the fastest access, the other has latched decoding.

Sorry Heater - I didn't mean to hijack your thread.


Links to other interesting threads:
Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/28/2009 5:40 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Dr_A: SD cards on the Prop for CP/M floppy and hard drives is already solved and done. Basically CP/M asks for sectors and we keep sectors in 512 byte blocks on SD card. (Or was it 256, I forget now). There is some wastage for the floppy disks that have 128 or so byte sectors but we can afford it in a 2GByte SD card:)

I will try and implement LDIR and friends as high speed PASM.

I want those 2M RAMS. Good for a 1M RAM disk and possibly a smaller one as well. Latched decoding for a RAM disk is just fine.

Cluso: You are by no means hijacking.


For me, the past is not over yet.

Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/28/2009 7:11 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Was just fishing around to save some LONGs. In the process managed to get the single COGs increment register (INR B) and jump 0000 loop emulation up to 416KIPS.
The 4 COG emulator only managed 414KIPS on that! I'm not depressed any more.

70 odd LONGs free. Squeezing the the last of the Z80 stuff in without a little overlay cheating may be getting a bit tight.


For me, the past is not over yet.

Back to Top
 

Ale
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined May 2007
Total Posts : 1534
 
   Posted 2/28/2009 9:23 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
heater: I saw that you picked a name already, great start.

In the implementation of daa I think you could compare data_8 directly against 100 ($A0) without moving it to nibble and shifting it right 4 bits (line 517 of your v 0.0). The mux instructions sure were handy!
Back to Top
 

Lawson
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Aug 2006
Total Posts : 318
 
   Posted 2/28/2009 9:40 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
heater said...
kwinn: Thank you. I think that's what they call "data driven programming" or at least "table driven"

Anyway it should be in every "Software Engineering 101" course to identify your primitive operations first and then design the code to use them.

It is fortuitous that the 8080/Z80 fits this scheme so well. We only have three vectors to play with in each table entry. With the 8080 you can get away with just "source", "operation" and "destination". As most operations work on the Accumulator (The A register) e.g. "ADD A, B" it does not need to specified in the table. Operations like "INR D" can work on any register/memory location, but here we only have one source and dest and they are always the same place.

Had the 8080 been like some CPU architectures and have two sources and a destination like "ADD dest, src1, src2" we would be out of luck.

James: "Pnut-Emu" What the..?


I don't thing we'd be completely out of luck if 4 pointers were needed per op-code. In that case using four 8-bit pointers could work IF the missing bit could be implied. (i.e "banking" the code into low and high sections based on op-code sub part, or table pointers only go to even addresses) Otherwise, the 4th pointer could just be restricted to a 5-bit sub-section of a cog's address space. Could be a royal pain to get the compiler to do this automatically. (haven't dived that deep into assembly yet)

Lawson


Lunch cures all problems! have you had lunch?

Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 2/28/2009 10:22 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
I guess it might be possible under some circumstances. Say if you functions happily divide into four equal sized COG areas. Using even addresses only could waste a lot of LONGs if you have many functions. A five bit subsection is only 32 LONGS so would work for a few short functions.

Hey, this thing gives me a big enough headache already:)


For me, the past is not over yet.

Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 3/1/2009 1:08 PM (GMT -7)    Quote This PostAlert An Admin About This Post.
Attached is the Zicog Z80 emulator wrapped up in a demo which can be run on a PropDemo board using PropTerminal (Easily changed to keyboard and TV_Text).

When the demo is run it shows the Z80 registers and steps through a short Z80 program loop when any key is hit. You can see the Z80 program in zicog_demo.spin.

The main point here is to show that Z80 ops with prefix bytes (CD, DD, FD, ED) are handled with the appropriate dispatch tables being used.

75% of the 8080 ops have been tested but only a handful of the Z80 ops. Almost all ops have some code in place but there is work to do on the Z80 flag settings.

Despite my optimism it looks as if we are going to be a few LONGs short of getting everything in the COG. There are only 66 LONGs left. So somethings will have to be farmed out to LMM or overlay. However I will keep the Z80 string moves LDIR, LDDR and string seaches CPIR, CPDR as high speed PASM as they are the only Z80 ops known to be used regularly.


For me, the past is not over yet.



File Attachment :
zicog_demo_v0_0.zip   113KB (application/zip)
This file has been downloaded 238 time(s).
Back to Top
 

heater
Registered Member



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Feb 2008
Total Posts : 3345
 
   Posted 3/4/2009 9:37 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Once again I owe a huge debt of gratitude to Cluso. This time it is for his PASM overlay loader.

ZiCog V0.1 (attached) has a version of the overlay loader shoehorned in where it is serving up overlays to handle the seldom used but long winded DAA instruction emulation. It is also catering for the 16 Z80 string move, compare, input and output instructions. LDIR and friends.

Whilst I wanted to keep the string ops in resident PASM it turns out they become quite huge. Still this may be a happy compromise as the overhead of loading a short overlay for each string op is (hopefully) not so burdensome when moving/comparing long strings. Certainly much faster than using LMM.

I have made some modifications to the overlay handler:
1. The overlays parameters are stored in a table in HUB rather than in COG.
2. Rather than use two instructions to load and execute each overlay I have arranged to have a single function do this, which is in turn called
via vectors in the dispatch tables with a parameter indicating which overlay to execute from the HUB table.

With these two changes any number of overlays can be used without eating additional COG space.

The attached demo runs a program of misc Z80 ops. It nicely shows LDIR moving a code block from 0000 to 0100 where it is then executed.

As usual any suggestions are welcome.


For me, the past is not over yet.



File Attachment :
zicog_demo_v0_1.zip   122KB (application/zip)
This file has been downloaded 232 time(s).
Back to Top
 

Cluso99
We live onboard



Email Address Not AvailablePersonal Homepage Not AvailablePrivate Messaging Not AvailableAIM Not AvailableICQ Not AvailableY! Not AvailableMSN Not Available
Date Joined Apr 2008
Total Posts : 4114
 
   Posted 3/4/2009 11:30 AM (GMT -7)    Quote This PostAlert An Admin About This Post.
Heater: Glad it was useful for you :-) Can't wait to get my TriBladeProp running your ZiCog (and other emulations) :-)
I asked about RED and it was going to cost an extra $2 per board - ouch! Obviously it's a pain for them to change.


Links to other interesting threads:
Back to Top
 
[ << Previous Thread | Next Thread >> ]
New Topic Post Reply Printable Version
1085 posts in this thread.
Viewing Page :
 
 
Forum Information
Currently it is Thursday, July 29, 2010 5:16 PM (GMT -7)
There are a total of 462,439 posts in 62,066 threads.
In the last 3 days there were 90 new threads and 802 reply posts. View Active Threads
Who's Online
This forum has 20143 registered members. Please welcome our newest member, ME01.
57 Guest(s), 9 Registered Member(s) are currently online.  Details
John Abshier, Rayman, kf4ixm, BradC, Sapieha, Gene Bonin, laser-vector, localroger, Nick McClick