ZZ80RC, a hobbyist-friendly, CP/M-ready Z80 SBC in RC2014 form factor

1,505 views
Skip to first unread message

Bill Shen

unread,
Aug 1, 2018, 10:47:34 PM8/1/18
to RC2014-Z80
ZZ80RC is an answer to my own 'challenge' of building a hobbyist-friendly, CP/M-ready Z80 SBC in the standard RC2014 (50mmx100mm) format. https://groups.google.com/forum/m/#!topic/rc2014-z80/AhgK3HCx2ng

This deviates from my normal designs which general have many surface mount components.  In general I find surface mount components easier to design and assemble than through-hole components, but I also know most hobbyists shy away from boards with SMT components.  So here is a design that uses only through-hole components and in the form factor of the standard RC2014 board.  

It is a single-board computer based on Z280.  It uses Z280's Bus Option feature to select the 8-bit Z80 Bus mode. In this mode, it still have many extended features of Z280, but the interface is Z80 bus compatible.  To squeeze the design into RC2014 form factor with through-hole components, I utilize several Z280 features:

1. Serial bootstrap,
2. Non-volatile RAM,
3. Built in MMU

Serial bootstrap is an unusual feature of Z280 that allows booting from the internal serial port after a reset.  With the data bus bit AD(6) set high and nWAIT asserted at reset, Z280 will enter the serial bootstrap mode where the CPU is suspended waiting for 256 bytes of instructions to be uploaded via the internal serial port to location 0x0-0xFF.  When the 256th byte of instruction is received , the CPU will start program execution from 0x0.  This feature requires a RAM located in the low memory.  A non-volatile RAM (battery or supercap backed) would allow program to be loaded serially when the system is powered up the first time and then changed back to normal bootstrap mode for subsequent operations.  Once the boot software is loaded into non-volatile RAM, it needs to be protected from being overwritten and the memory free up for other applications, such as CP/M.  Z280's MMU can write protect the physical boot page (page 0) and map another physical page to logical page 0.  At reset, MMU is disabled and Z280 boots from the physical page zero;  the software in page 0 then enables the MMU, write protect the physical page zero, maps another physical page to logical page zero, loads CP/M, and jump into CP/M. This way CP/M will have unfettered access to the entire logical 64k memory.  With Z280's MMU and/or DMA capabilities, the remaining 512k RAM memory is accessible via BIOS calls as drive A: (CP/M file system) and drive B: (RAM disk).

Since the board size is 100mm x 50mm, I can step-and-repeat the artwork and put two designs on a 100mm x 100mm board. However, there are not much space between the two designs to cut by hand. Buried deep in Seeed Studio's PCB instruction is a guide to V-Cut a 100mm x 100mm board into multiple identical designs and still charge $5 for the base 100mm x 100mm boards. I only need to generate a .GKO file that shows where to V-Cut the board. I'll try that and see how that works out.

ZZ80RC_scm.pdf
ZZ80RC_gerber.pdf
ZZ80RC_v_cut.pdf

Mark T

unread,
Aug 1, 2018, 11:57:36 PM8/1/18
to RC2014-Z80
I think I might need one of these after I finish a few z80 projects that I'm still working on.

If you can't use v-score with seed you might try jlcpcb, they allow 102mm x 102mm panel before increasing cost, so you can panel your board to 100 x 102 and allow a 2mm gap for cutting. I think they will add cost for v-score, drilling or routing for depanelisation, but you can put 2mm wide routing by 13mm at each side to act as a guid for starting the cut. I've used this on a couple of panels already.

Bill Shen

unread,
Aug 2, 2018, 8:41:02 AM8/2/18
to RC2014-Z80
When I have the design working, I'll publish all design information and put them in the public domain just like all my other designs.  Anyone can build their own board with these information.  I can also provide kits or even assembled/tested board.

The 102mm x 102mm is a good option.  Right now all my RC2014 board has the 40th pin hanging out connected only by the plastic strip.  My designs generally have a power & ground rings at the board edge, with 102mm I can have wider power/ground rings and mounting holes.
  Bill

Alan Cox

unread,
Aug 2, 2018, 8:52:14 AM8/2/18
to rc201...@googlegroups.com
I take it you've read the errata on the Z80 bus mode, in particular
the cache on the CPU is basically unusable at least as far as Rev G
(Feb 1988). I don't know if the later revisions ever happened, or ever
fixed it but if it's showing random memory corruption type behaviour
when you test and have cache on you have a suspect!

Alan

Bill Shen

unread,
Aug 2, 2018, 9:18:27 AM8/2/18
to RC2014-Z80
Alan,
Thanks for the heads up, no I'm not aware of the cache problem.  I'll find out soon, probably this weekend.  I'm optimistic, however; tinkering with Z280 in the last 9 months I realized that most of the reported bugs have been fixed, at least for Z280 with date code of 1992 or later.
  Bill

Mark T

unread,
Aug 2, 2018, 2:29:31 PM8/2/18
to RC2014-Z80

It might look nicer in a system if it could copy the shape of the RC2014 modules. I've used 50 x 100 mm but set the left edge, height and pin one cutoff to match the RC2014 modules, using 50 x 102 could do the same and include pin 40. It might mean losing the power jack to fit into the shape.

It would also be good to include the RC2014 enhanced bus for additional addressing.

Is there any possibility of using zbus with the rc2014 enhanced bus?

Mark


Bill Shen

unread,
Aug 2, 2018, 7:33:11 PM8/2/18
to RC2014-Z80
Mark,
To have rounded top back corner and diagonal front corner means one of the sub-design need to be rotated 180 degree so the V-cut line is along the RC2014 connector side.  I'll figure out how to do that in the next board revision.  The power jack is for standalone operation without the RC2014 backplane.  I plan to leave the power jack as is, but just make the diagonal board outline cut and do not populate the power jack when used as a RC2014 module.  When operating the board in the standalone mode, I can still populate the power jack.  Another possible variation is to leave the basic design as is but make the board 102mm x 102mm and add 2 more RC2014 connectors so this becomes an active backplane with 3 RC2014 expansion slots.

To save on components, the address space of 512K RAM is not decoded.  Another word, the same 512K RAM is aliased 32 times across Z280's 16-meg memory space.  Since the entire memory space is already consumed, there is no point in bringing out additional address lines.  In fact, address lines A8-A15 are really unnecessary in the current design.  Of course this is an artifact of current design which can be changed at will.

Z280RC module operates in the 16-bit Z-bus mode, but it already has 2-meg of memory so I don't feel it is necessary to add more memory through the RC2014 enhanced bus.  I think it is difficult to use the enhanced bus without going surface mount or larger pc board format.
  Bill

Bill Shen

unread,
Aug 3, 2018, 2:17:36 PM8/3/18
to RC2014-Z80
Here is the 100mm x 100mm pc board with two ZZ80RC designs.  The v-cut line is very narrow and fits right between the small space between the two designs.  Bending the board causes it to snap cleanly right along the v-cut.  The traces are only few mils from the v-cut but are not damaged by the snapping apart of the board.  Impressive, but it is too close for comfort.  Next time I'll have a little more clearance between designs.

It took about an hour to gather all the parts and solder up a board.  Anxious to try it out this weekend.


DSC_37240803.jpg
DSC_37270803.jpg
DSC_37290803.jpg

Bill Shen

unread,
Aug 3, 2018, 8:04:39 PM8/3/18
to RC2014-Z80
I have not received DS1210 yet, so I just jumper VCC to RAM power, and jump across the chip selects in & out.  Power it up and it runs!  Power consumption is 140mA at 5V which means it can be powered with just the USB adapter.  The serial bootstrap program is the same software from Z280RC.  There are incompatibilities in fuctionalities, but the core bootstrap function is the same.  The hex file loader works the same so I can load Steve Cousins' SCMonitor (the Z280RC version) and run it and it works also.  There are also incompatibilities but the core SCMonitor only uses the serial port so function like BASIC should work with ZZ80RC. With that in mind I loaded & ran a couple benchmarks: karlab's prime number generator (https://groups.google.com/forum/#!topic/rc2014-z80/oXtvYk1T0c8) and Mandelbrot ASCII art.  They both run fine.  That was easy!

In reality there are lots of software works ahead, but it is nice to know the basic hardware functionalities are working.
  Bill


..........................................................................................................................................................................UX
TinyZZ Monitor v0.99 6/9/18

>help
G <addr> CR
R <track> <sector>
D <start addr> <end addr>
Z CR
F CR
T CR
E <addr>
X <options> CR
B <options> CR
C <options> CR

>........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................X

>

>go to address: 0x0000 press Return to execute command

Small Computer Monitor - RCZ280
*help
Small Computer Monitor by Stephen C Cousins (www.scc.me.uk)
Version 1.0.0 configuration Z1 for Bill Shen's Z280 based RCZ280 system

Monitor commands:
A [<address>]  = Assemble        |  D [<address>]   = Disassemble
M [<address>]  = Memory display  |  E [<address>]   = Edit memory
R [<name>]     = Registers/edit  |  F [<name>]      = Flags/edit
B [<address>]  = Breakpoint      |  S [<address>]   = Single step
I <port>       = Input from port |  O <port> <data> = Output to port
G [<address>]  = Go to program
BAUD <device> <rate>             |  CONSOLE <device>
FILL <start> <end> <byte>        |  API <function> [<A>] [<DE>]
DEVICES, DIR, HELP, RESET
BASIC    Grant Searle's adaptation of Microsoft BASIC
WBASIC   Warm start BASIC (retains BASIC program)
CPM      Load CP/M from Compact Flash (requires prepared CF card)
*basic

Memory top?
Z80 BASIC Ver 4.7b
Copyright (C) 1978 by Microsoft
47811 Bytes free
Ok
10 CLS
20 PRINT "limit";
30 INPUT L
40 FOR N=3 TO L
50 FOR D=2 TO (N-1)
60 IF N/D=INT(N/D) THEN GOTO 100
70 NEXT D
80 PRINT N;
90 GOTO 110
100 PRINT ".";
110 NEXT N
120 END
run

limit? 1000
 3 . 5 . 7 ... 11 . 13 ... 17 . 19 ... 23 ..... 29 . 31 ..... 37 ... 41 . 43 ... 47 ..... 53 ..... 59 . 61 ..... 67 ... 71 . 73 ..... 79 ... 83 ..... 89 ....... 97 ... 101 . 103 ... 107 . 109 ... 113 ............. 127 ... 131 ..... 137 . 139 ......... 149 . 151 ..... 157 ..... 163 ... 167 ..... 173 ..... 179 . 181 ......... 191 . 193 ... 197 . 199 ........... 211 ........... 223 ... 227 . 229 ... 233 ..... 239 . 241 ......... 251 ..... 257 ..... 263 ..... 269 . 271 ..... 277 ... 281 . 283 ......... 293 ............. 307 ... 311 . 313 ... 317 ............. 331 ..... 337 ......... 347 . 349 ... 353 ..... 359 ....... 367 ..... 373 ..... 379 ... 383 ..... 389 ....... 397 ... 401 ....... 409 ......... 419 . 421 ......... 431 . 433 ..... 439 ... 443 ..... 449 ....... 457 ... 461 . 463 ... 467 ........... 479 ....... 487 ... 491 ....... 499 ... 503 ..... 509 ........... 521 . 523 ................. 541 ..... 547 ......... 557 ..... 563 ..... 569 . 571 ..... 577 ......... 587 ..... 593 ..... 599 . 601 ..... 607 ..... 613 ... 617 . 619 ........... 631 ......... 641 . 643 ... 647 ..... 653 ..... 659 . 661 ........... 673 ... 677 ..... 683 ....... 691 ......... 701 ....... 709 ......... 719 ....... 727 ..... 733 ..... 739 ... 743 ....... 751 ..... 757 ... 761 ....... 769 ... 773 ............. 787 ......... 797 ........... 809 . 811 ......... 821 . 823 ... 827 . 829 ......... 839 ............. 853 ... 857 . 859 ... 863 ............. 877 ... 881 . 883 ... 887 ................... 907 ... 911 ....... 919 ......... 929 ....... 937 ... 941 ..... 947 ..... 953 ............. 967 ... 971 ..... 977 ..... 983 ....... 991 ..... 997 ...
Ok

10 for y=-12 to 12
20 for x=-39 to 39
30 ca=x*0.0458
40 cb= y*0.08333
50 a=ca
60 b=cb
70 for i=0 to 15
80 t=a*a-b*b+ca
90 b=2*a*b+cb
100 a=t
110 if (a*a+b*b)>4 then goto 200
120 next i
130 print " ";
140 goto 210
200 if i>9 then i=i+7
205 print chr$(48+i);
210 next x
220 print
230 next y
run
000000011111111111111111122222233347E7AB322222111100000000000000000000000000000
000001111111111111111122222222333557BF75433222211111000000000000000000000000000
000111111111111111112222222233445C      643332222111110000000000000000000000000
011111111111111111222222233444556C      654433332211111100000000000000000000000
11111111111111112222233346 D978 BCF    DF9 6556F4221111110000000000000000000000
111111111111122223333334469                 D   6322111111000000000000000000000
1111111111Æ22333333334457DB                    85332111111100000000000000000000
11111122234B744444455556A                      96532211111110000000000000000000
122222233347BAA7AB776679                         A32211111110000000000000000000
2222233334567        9A                         A532221111111000000000000000000
222333346679                                     9432221111111000000000000000000
234445568  F                                   B5432221111111000000000000000000
                                             
864332221111111000000000000000000
234445568  F                                   B5432221111111000000000000000000
222333346679                                    9432221111111000000000000000000
2222233334567        9A                         A532221111111000000000000000000
122222233347BAA7AB776679                         A32211111110000000000000000000
11111122234B744444455556A                      96532211111110000000000000000000
1111111111222333333334457DB                    85332111111100000000000000000000
111111111111122223333334469                 D   6322111111000000000000000000000
11111111111111112222233346 D978 BCF    DF9 6556F4221111110000000000000000000000
011111111111111111222222233444556C      654433332211111100000000000000000000000
000111111111111111112222222233445C      643332222111110000000000000000000000000
000001111111111111111122222222333557BF75433222211111000000000000000000000000000
000000011111111111111111122222233347E7AB322222111100000000000000000000000000000


Ok

DSC_37300803.jpg

Bill Shen

unread,
Aug 5, 2018, 7:00:40 PM8/5/18
to RC2014-Z80
Received DS1210 and installed it along with a super capacitor.  I now have non-volatile RAM that should last for a week or so.  Downloaded the Super Star Trek program from here:
https://github.com/linker3000/Z80-Board
It seems to run fine with SCMonitor's Z80 BASIC ver 4.7b



                                                         
,------*------,
                                         
,-------------   '---  ------'
                                         
'-------- --'      / /
                                             
,---' '-------/ /--,
                                               
'----------------'








YOUR ORDERS ARE AS FOLLOWS
:
--------------------------
   DESTROY THE
19 KLINGON WARSHIPS WHICH HAVE INVADED
   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS
   ON STARDATE
2428. THIS GIVES YOU 28 DAYS. THERE ARE
   
3 STARBASES IN THE GALAXY FOR RESUPPLYING YOUR SHIP.

PRESS Y TO ACCEPT COMMAND
? y


YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED
IN THE GALACTIC QUADRANT
, 'CAPELLA I'.

   
+--1---2---3---4---5---6---7---8-+
 
1 |                         <E>  * | 1         STARDATE           2400
 
2 |                                | 2         CONDITION          GREEN
 
3 |      *               *         | 3         QUADRANT            3, 5
 
4 |                  *             | 4         SECTOR              1, 7
 
5 |                                | 5         PHOTON TORPEDOES   10
 
6 |                      *         | 6         TOTAL ENERGY       3000
 
7 |          *   *   *             | 7         SHIELDS            0
 
8 |                                | 8         KLINGONS REMAINING 19
   
+--1---2---3---4---5---6---7---8-+

COMMAND
? help

ENTER ONE OF THE FOLLOWING
:
--------------------------
  NAV  
(TO SET COURSE)
  SRS  
(FOR SHORT RANGE SENSOR SCAN)
  LRS  
(FOR LONG RANGE SENSOR SCAN)
  PHA  
(TO FIRE PHASERS)
  TOR  
(TO FIRE PHOTON TORPEDOES)
  SHE  
(TO RAISE OR LOWER SHIELDS)
  DAM  
(FOR DAMAGE CONTROL REPORTS)
  COM  
(TO CALL ON LIBRARY-COMPUTER)
  XXX  
(TO RESIGN YOUR COMMAND)


karlab

unread,
Aug 6, 2018, 4:11:28 AM8/6/18
to RC2014-Z80
Hi Bill
Great module design, perfect for troubleshooting the bus or other modules.
Have you considered selling your Z280 module?
I wouldn't mind buying one, assembled or in parts.
Karl

Bill Shen

unread,
Aug 6, 2018, 7:56:25 AM8/6/18
to RC2014-Z80
Z280RC has surface mount components so I don't sell them as kit but do sell them assembled and tested for $50 plus shipping.  PM me your address if you are interested.
https://groups.google.com/forum/#!topic/rc2014-z80/daMHYeqO6-4

ZZ80RC has all through-hole components so anyone can build it.  The design works well enough that I'm posting the gerber files below.  I also have 11 extra boards so if you (anyone, not just karlab) are in the USA, PM me your address and I'll drop off a bare pc board in the mail free.  Shipping outside USA is too expensive, you are better off ordering the pc board from Seeed (or others pc board makers).   I'll publish the bill-of-material soon.  I have enough parts for two kits, the kit price is $26 due to a couple expensive items (AS6C4006 and DS1210).
  Bill
ZZ80RC_rev0.zip

Bill Shen

unread,
Aug 6, 2018, 1:57:25 PM8/6/18
to RC2014-Z80
Attached is the bill of material for rev 0 of ZZ80RC
  Bill
zz80rc_r0.bom

Bill Shen

unread,
Aug 11, 2018, 6:48:31 PM8/11/18
to RC2014-Z80
Those who have my ZZ80 pc boards, I have added a pictorial build instruction here:
https://www.retrobrewcomputers.org/doku.php?id=builderpages:plasmo:zz80rc:zz80rc_buildlog

Going up one level is ZZ80RC wiki page.  I'm updating it periodically.

CP/M2.2 is working now.  Attached are two HEX files, first file (loadcpm.hex) loads CP/M CCP, BDOS, BIOS into memory and also clear drive B directory.  The second file (cpm22dri.hex) loads CP/M2.2 system files plus XMODEM and MBASIC80 to drive A.  At 115200 baud both files load in about 40 seconds or so.  After both files are loaded, type gf200 to start CP/M2.2
you should see

>go to address: 0xf200 press Return to execute command
Copyright 1979 (c) by Digital Research
CP
/M 2.2 for ZZ80RC
8/10/18 256K RAMDisk

a
>dir
A
: ASM      COM : BIOS     ASM : CBIOS    ASM : DDT      COM
A
: DEBLOCK  ASM : DISKDEF  LIB : DUMP     COM : DUMP     ASM
A
: ED       COM : LOAD     COM : MOVCPM   COM : PIP      COM
A
: STAT     COM : SUBMIT   COM : SYSGEN   COM : XSUB     COM
A
: XMODEM   COM : MBASIC80 COM : STARTREK TXT : ASCIIART TXT



Drive A is pretty much full, but there are 256K space on drive B.  XMODEM works well, but you may want to include /z1 switch otherwise you need to pick the file quickly before XMODEM starts.  The command is
XMODEM filename /R/C/Z1    you have 15 seconds or so before file transfer start, so be ready. 

MBASIC80 works well, I added a startrek program, startrek.txt.  The command is
MBASIC80 startrek.txt

b>mbasic80 startrek.txt
BASIC
-80 Rev. 5.21
[CP/M Version]
Copyright 1977-1981 (C) by Microsoft
Created: 28-Jul-81
32824 Bytes free



THE USS ENTERPRISE
--- NCC-1701


                                                       
,------*------,
                                       
,-------------   '---  ------'
                                         
'-------- --'      / /
                                             
,---' '-------/ /--,
                                             
'----------------'

YOUR ORDERS ARE AS FOLLOWS
:
--------------------------
   DESTROY THE
19 KLINGON WARSHIPS WHICH HAVE INVADED
   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS
   ON STARDATE
2428. THIS GIVES YOU 28 DAYS. THERE ARE
   
3 STARBASES IN THE GALAXY FOR RESUPPLYING YOUR SHIP.

PRESS Y TO ACCEPT COMMAND
? y


YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED
IN THE GALACTIC QUADRANT
, 'CAPELLA I'.

   
+--1---2---3---4---5---6---7---8-+
 
1 |                         <E>  * | 1         STARDATE           2400
 
2 |                                | 2         CONDITION          GREEN
 
3 |      *               *         | 3         QUADRANT            3, 5
 
4 |                  *             | 4         SECTOR              1, 7
 
5 |                                | 5         PHOTON TORPEDOES   10
 
6 |                      *         | 6         TOTAL ENERGY       3000
 
7 |          *   *   *             | 7         SHIELDS            0
 
8 |                                | 8         KLINGONS REMAINING 19
   
+--1---2---3---4---5---6---7---8-+


COMMAND
? LRS

LONG RANGE SCAN FOR QUADRANT
3, 5

-------------------
| 007 | 003 | 003 |
-------------------
| 001 | 008 | 003 |
-------------------
| 308 | 001 | 005 |
-------------------




I'm still working on a bootstrap monitor so right now you'll need to load loadngo.run every time you cycle power or press reset (remember to add 1msec/line in transmit delay and check the 'binary' option, which is needed only for loading loadngo.run).  You generally don't need to load loadcpm.hex or cpm22dri.hex. 

I'm a bit disappointed with Super capacitor memory retention.  It is only good for 2-3 days.  So even with working bootstrap monitor, the board will need to load all software after 2-3 days of power off.  I probably will go to battery backup on next iteration.

  Bill

PS, I still have 5 bare pc boards free to USA RC2014 members, just PM me your address

loadcpm.zip
CPM22DRI.zip

Jeff Greer

unread,
Aug 11, 2018, 8:54:09 PM8/11/18
to rc201...@googlegroups.com
Good evening Bill,

I received my board Thursday. It is very nice and well designed. The solder mask is professional grade. I am going to start ordering the parts this weekend.

Thank you!

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+unsubscribe@googlegroups.com.
To post to this group, send email to rc201...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/rc2014-z80/958548cc-9ae8-4e34-a2c7-0df25d786004%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Bill Shen

unread,
Aug 11, 2018, 9:42:50 PM8/11/18
to RC2014-Z80
Jeff,
Thanks for letting me know you've received the board in good shape. 

The board in the pictorial construction log is the 4th one I built.  All four boards work just fine.  There are no engineering change so far.  Only thing I'm not happy about is the super capacitor retention time, but since a complete reload of software is only about 40 seconds, and the super cap will retain the memory for a few days, it is probably not a big issue.

Good luck with your build, please let me know how it goes.
  Bill

Bill Shen

unread,
Aug 13, 2018, 10:42:00 PM8/13/18
to RC2014-Z80
I've reached the stated goal which is the title of this topic!

Documentation for ZZ80RC is here:
https://www.retrobrewcomputers.org/doku.php?id=builderpages:plasmo:zz80rc

For people building the board, please refer to the pictorial build log:
The Getting Started guide has instruction on how to install/operate the various software:
https://www.retrobrewcomputers.org/doku.php?id=builderpages:plasmo:zz80rc:getting_started

Please ignore the instruction and attached files in previous message (message dated August 11).  That was a band-aid solution for people who has ZZ80RC board assembled and eager to try out software.

This is the initial release of the design files.  I'm sure there will be many more revisions.  Feedback are appreciated!
 
  Bill

Alan Cox

unread,
Aug 14, 2018, 6:29:08 AM8/14/18
to rc201...@googlegroups.com
Nice - that really begs wiring the onboard serial port to an arduino
board along with the boot switch so that they can be wired to fake
front panel to type in the hex to boot it from compact flash 8)

Alan

Bill Shen

unread,
Aug 14, 2018, 8:18:21 AM8/14/18
to RC2014-Z80
Two of the 4 DMA channels can be dedicated to the UART's transmit and receive channels, so it is possible to run the UART at much higher clock rate.  With the appropriate SPI-to-serial converter, it is not unreasonable to have SD card as the boot device and continue to serve as the mass storage device. 
I have a separate clock for the UART because I think the serial port can be the high speed communication backbone for multiprocessor instead of the lowly user console.  How do you connect serial port to TCP/IP?
  Bill

Alan Cox

unread,
Aug 14, 2018, 8:43:48 AM8/14/18
to rc201...@googlegroups.com
> I have a separate clock for the UART because I think the serial port can be
> the high speed communication backbone for multiprocessor instead of the
> lowly user console. How do you connect serial port to TCP/IP?

The modern way is a protocol called PPP, the old (and far simpler and
better suited to 8bit micros) is a protocol called SLIP which
basically wraps TCP/IP into a simple serial protocol with end markers
for packets and escaping so end marks don't appear anywhere else. It's
then easy enough to set up a Linux box to act as a gateway - dunno
about Windows. I'm sure you can but don't ask me how!

At minimum SLIP sends each packet by sending 0xC0 then the TCP/IP
packet then 0xC0. If any character in the packet is 0xC0 it sends 0xDB
0xDC instead, if any character is 0xDB it sends 0xDB 0xDD. On receipt
if you get lost it doesn't matter as the next 0xC0 puts you back in
sync.

Classic multiprocessor is usually about latency not bandwidth though
hence shared memory. Loose coupled multi-processors (aka clustered)
you probably could do that way with serial and DMA. Some multi-user
CP/M systems worked this way - the one big expensive hard disk sat
next to a CPU that ran MP/M, and the other processors talked over a
fast serial link to it and ran CP/M or CP/N (CP/M + CP/NET in ROM
with no local devices). Various old systems also used to support RS485
style serial as cheap inter-machine networking (eg Apple Localtalk,
RabbitNet etc).

There also used to be big FIFO chips available for such applications I
don't know if they exist any more (7200 etc).

There are some more modern ways of doing internet connectivity. The
ESP8266 modules are dirt cheap wifi<->serial adapters although they
can be reprogrammed to do other stuff. They look like an AT modem one
side but instead of phone you can 'call' an internet IP address.

The WizNet modules provide wifi or fixed ethernet (eg WizNet 5300)
where the protocol stack and buffering is on the chip and you get like
8 connections at a time (plenty for an 8bit micro!) where you don't
have to do much work but request connections, check state and manage a
FIFO. You only need a few I/O ports for one. To me that still feels
perfectly retro. In 8bit days most fancy comms (X.25 etc) usually
involved a great big add in card that did all the work, or a separate
unit that had something like 16 serial ports and an X.25 interface.

I've also got an ancient MOXA Nport junk price off ebay which is great
as it has ethernet and 16 serial interfaces and you can telnet in (or
connect out) of each port according to how you set it up, and set
different baud rates/bit rates for each port.

Alan

Bill Shen

unread,
Aug 14, 2018, 2:44:19 PM8/14/18
to RC2014-Z80
Thanks for the many network suggestions.  The trouble with standards is there are so many to choose from!  Looks like I have quite a bit of readings to do.  I do have a WizNet board somewhere and that may be the best place to start.

I do like to explore a multi processor system, something I did in the 1980's but that was based on 680x0 processors.  Z280 have the atomic test & set instruction and large memory space for the shared memory model so it is a good candidate.

  Bill

Bill Shen

unread,
Sep 19, 2018, 8:42:08 PM9/19/18
to RC2014-Z80
This is another reason why I love the original RC2014 single-row connector: with a single-board RC2014 computer, you can plug it into a solderless breadboard and do experiments.  The board in the picture is hanging out of the edge because with on-board memory, the high memory signals A8-A15 are not needed, so only 26 RC2014 signals are required, this leaves plenty of room for experiments even on a small breadboard.  This particular breadboard setup is ZZ80RC testing a simplified version of Ed Brindley's YM2149/AY-3-8910 sound card. 

DSC_38050919.jpg

Steve Cousins

unread,
Sep 20, 2018, 4:15:24 AM9/20/18
to RC2014-Z80
Hi Bill

I've been warming to the single row connector recently.

Initially I wanted to go 100% enhanced bus. More recently I have been building with two full rows (80-pins). However, I have been getting increasing put off the 80-pin connectors due to the difficulty of pulling them apart. I think they work great for a system that is left connected, but I'm constantly swapping boards about. By the time you get to 80-pins you really want some sort of card extraction 'lever'. Some card systems have these, but I can't see a sensible way to add them to the RC2014.

It seems to me that your designs with the CPU and memory on a single card mean the module connector really only needs to be for I/O, as you indicate in your example. OK, there are a few things that require access to the full memory bus, but very few. Seems wrong to run all those memory related signals all the way up the bus. Think of all the wasted soldering!

For stability you want two rows of pins. For simplicity and ease of experimenting you want one row of pins. For ease of extraction you want a short row of pins. A short row means you can get your finger tips under each end of the PCB and wiggle it out. So no simple solution is perfect.

Your 26 pins is a pretty good solution for experimenting and prototyping.

Steve

Mark T

unread,
Sep 20, 2018, 10:02:35 AM9/20/18
to RC2014-Z80
Some kind of ZIF connector would be really nice. Closest I've seen was 36 way SIL which might be OK for single row connector if the user pins were removed but they were a bit too expensive.

I was thinking it may be possible to make a simple zif, using two or three backplane pcbs without connectors in a sandwich configuration, possibly with spacers. Plug the module directly into the backplane socket through holes, then force an offset onto one of the backplane pcbs. This would probably have to slightly deform the pins of the module to apply force to every connection. I didn't try to build it because the effort to build it was probably greater than the expected life of the connections.

Mark

Bill Shen

unread,
Sep 20, 2018, 10:36:30 AM9/20/18
to RC2014-Z80
Steve,
Funny how with a bit of time, we may come around to different ideas.  I myself am warming up to the extended RC2014 bus and thinking of a 16-bit design based on Z280 that uses extended addresses & data bus signals.  I know I've already done a 16-bit Z280 design, but it is not at all hobbyist-friendly.  The new design will be through-hole technology only.  I hope it will serve as an example for future 16-bit designs.

This is the tool I used to lift boards off new backplane, but now the connector has loosen up with use so I just pull the board off by hand. 
  Bill
board_lifter_F.jpg

Steve Cousins

unread,
Sep 20, 2018, 11:05:09 AM9/20/18
to RC2014-Z80
The grass is always greener on the other side, so we are constantly climbing fences.

Bill Shen

unread,
Nov 5, 2018, 11:42:20 AM11/5/18
to RC2014-Z80
A quick update of ZZ80RC just so I don't hijack Steve Cousins' excellent topic on "A simpler '14":
I did a quick tally of my projects in the past 2 years and realized I've built 24 different projects, among them are 15 RC2014 projects.  So I'm slowly migrating my project pages out of retrobrewcomputers into GitHub where software updates are easier to manage.  There is a GitHub project page for ZZ80RC (https://github.com/Plasmode/ZZ80RC).  I'll finish adding software to it in the next few days.

If you have Spencer's CF board and a working ZZ80RC, please let me know.  I have a version of CP/M 2.2 that works with a prototype CF module but I don't have the official RC2014 CF board and like someone to test it out.

A member had a batch of 20 ZZ80RC boards made and was kind enough to send me 10 of the boards, so I have a dozen bare PC boards to give away to anyone in USA. 
  Bill

Bill Shen

unread,
Nov 25, 2018, 10:27:57 PM11/25/18
to RC2014-Z80
ZZ80RC can talk to compact flash module quite nicely and I have CP/M 2.2 & 3 running.  It occurs to me the CF interface logic is simple enough that it can fit in the ZZ80RC footprint (50x100mm).  This is also an opportunity to get rid of the super capacitor and replace it with the CR1210 battery.  This is still all thru-hole technology except the CR1210 battery holder and CF adapter but they are easy to solder.
  Bill

ZZ80RC_r1_Seeed.jpg
ZZ80RC_r1_scm.pdf

karlab

unread,
Nov 26, 2018, 4:26:17 PM11/26/18
to RC2014-Z80
Hi Bill 
I just want to inform you that I finished building your zz80rc (I see you have made a new version).
I have done minimal testing so far, loaded the bootstrap loader, and have loaded and run cp/m 2.2.
It looks good so far. The documentation is good. Obtaining all parts is the hardest bit in my mind.
Cheers
Karl

Bill Shen

unread,
Nov 26, 2018, 9:20:37 PM11/26/18
to RC2014-Z80
Karl,
Thanks for letting me know about your ZZ80RC experience.  I find the supercap only able to retain the data for 2-3 days.  It is OK if you are working on the board everyday, but you'll need to go through the software loading process all over again if the board is set aside for a few days.  So I've redesigned it with a battery backup which should be good for at least a year.  You can also hand-wire the CR1210 battery holder instead of the supercap for current pc board.

If you have an official RC2014 CF board, I like you to try out a version of CP/M2.2 that uses the CF board.  I've built a CF prototype based on Spencer's published schematic, but it was problematic.  I re-deisgned the circuitry so it worked better, but it is still not perfect.  I'm curios whether the official RC2014 CF board works better.  I also hope the new ZZ80RC design with an integrated CF interface will work better than a separate CF board.
  Bill

Bill Shen

unread,
Nov 26, 2018, 9:51:05 PM11/26/18
to RC2014-Z80
Karl,
I just added the executable as well as assembly source of CPM22allCF0x10 for ZZ80RC with an official RC2014 CF board.  It is on my GitHub page, https://github.com/Plasmode/ZZ80RC  The installation process is the same, but instead of loading CPM22all.hex, load CPM22allCF0x10.hex.
  Bill

Greg Holdren

unread,
Nov 27, 2018, 2:52:11 AM11/27/18
to RC2014-Z80

Got my Rev0 going last weekend too. Thanks! I don't have the official CF board but I should be able to wire it up pretty quick to the backplane. I'll try the code out once I get the CF interface going.

Greg

Karl Albert Brokstad

unread,
Nov 27, 2018, 3:28:17 AM11/27/18
to rc201...@googlegroups.com
HI Bill

I will try later today, after work.

Karl

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+...@googlegroups.com.

To post to this group, send email to rc201...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

-----
Karl Albert Brokstad
Kirkeveien 9B, 5072 Bergen
98843314, 55289014
ka...@brokstad.no

karlab

unread,
Nov 27, 2018, 10:42:32 AM11/27/18
to RC2014-Z80
I am home and have tried the CF drive with zz80rc.

I am still very new to your module, so I may perform wrong operations.

loaded LoadnGo.hex (0.28)
>C0
>C2
>B2

I can see the a and b drives (ram drives)
I can see the D:, E:, F: ..... drives on a 128 MB CF (RC2014 SIO/2) card

when giving command DIR C: I get this
a>dir C:
C:   :   :   :  
C:   :   :   :   
C:   :   :   :  
C:   :   :   :  
C:   :   :   :  
C:   :   :   :  
C:   :   :   :  


Karl





Bill Shen

unread,
Nov 27, 2018, 10:57:32 AM11/27/18
to RC2014-Z80
Karl,
Yes, you are doing it correctly.  You should have drives C:, D:, E: which are 8-meg disks on the CF.  Does the CF contains important data?  If not, you can erase the directory with "era c:*.*" and then "pip c:=a:*.*[v]" to check whether the disk can be written and verify.
  Bill

Bill Shen

unread,
Nov 27, 2018, 11:02:01 AM11/27/18
to RC2014-Z80
This is my modified CF prototype board.  The modifications I find necessary is some setup time from CF select asserted to read/write assertion.  The spec calls for 30nS setup (in mode 2).  The other modification that are not strictly necessary but I find helpful is data bus serial termination (100ohm) and read signal filtering (100 ohm + 100pF RC network).  The CF disks can generate significant noise when all data lines are switching that disturbs the CF read signal.  If the connections are long with respect to the signal rise time, termination resistors are recommended.  Terminations are less important if the CF interface is located on the same board. 

I have 19 different brands of CF on hand.  With this CF prototype and without termination, only a few (mostly the Cisco brands) would work.  With termination and signal conditioning as shown in the pictures, 16 out of 19 work (by "work", I mean successful PIP copy *.* with verify).  However, 3 CF disks (last picture) still fail to verify.  I find the SanDisk 256meg (rightmost of last picture) is the most troublesome CF disk of my collection.  It fails all my designs except the Z80SBCRC.

There is hope, with Z80SBCRC where the CF interface is on the same board and short point-to-point wiring and without terminations or signal conditioning, all 19 brands of CF work.  I'm hoping version 1 of ZZ80RC where CF interface is on board will perform like Z80SBCRC.
  Bill

protoCF_scm.pdf
ProtoCF_comp.jpg
ProtoCF_solder.jpg
protoCF_working_CF.jpg
protoCF_failing_CF.jpg

Bill Shen

unread,
Nov 27, 2018, 11:18:34 AM11/27/18
to RC2014-Z80
I forgot to mention that the above testing were done with a ZZ80RC on a 5-slot RC2014 backplane.  Here is the picture of that setup.
  Bill
DSC_40551127.jpg

Karl A. Brokstad

unread,
Nov 27, 2018, 11:29:18 AM11/27/18
to rc201...@googlegroups.com
Just a quick question
Can i replace the super capacitor, and solder in a 5v or 3v battery directly to Its connector?
Karl

Sent from my iPad

On 27 Nov 2018, at 17:18, Bill Shen <coinst...@gmail.com> wrote:

I forgot to mention that the above testing were done with a ZZ80RC on a 5-slot RC2014 backplane.  Here is the picture of that setup.
  Bill

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+...@googlegroups.com.
To post to this group, send email to rc201...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
<DSC_40551127.jpg>

karlab

unread,
Nov 27, 2018, 12:01:05 PM11/27/18
to RC2014-Z80

erase c: and copied everything from a: to c:
worked like a charm
(used my 4mb CF card)
karl


Bill Shen

unread,
Nov 27, 2018, 12:06:55 PM11/27/18
to RC2014-Z80
Yes.  Here is a set of photos showing how to install 3V (CR1210) battery.
  Bill


On Tuesday, November 27, 2018 at 9:29:18 AM UTC-7, karlab wrote:
Just a quick question
Can i replace the super capacitor, and solder in a 5v or 3v battery directly to Its connector?
Karl

Sent from my iPad

On 27 Nov 2018, at 17:18, Bill Shen  wrote:
install CR1220 battery copy.jpg
ZZ80RC_with CR1210_comp.jpg
ZZ80RC_with CR1210_solder.jpg

Bill Shen

unread,
Nov 27, 2018, 12:10:56 PM11/27/18
to RC2014-Z80
Oops, I've said CR1210, but it is in fact CR1220 battery.
  Bill

Bill Shen

unread,
Nov 27, 2018, 12:13:50 PM11/27/18
to RC2014-Z80
Excellent!  4 mb CF card should work for a while until the disk is filling up, then it'll crash and likely corrupt your data.  It is a good test vehicle, however.
  Bill

Tom Szolyga

unread,
Nov 27, 2018, 6:39:08 PM11/27/18
to RC2014-Z80
Hi Bill,

I have had good success with a similar CF board design.  Instead of resistors I used a 74ALS245 bus transceiver.  It buffers/isolates the CF card data bus from the microprocessor data bus.  To connect the CF card, I use an IDE to CF card adapter I found on eBay.  The board has worked with every processor board, backplane board and CF card I have tried. 

Tom
IDE CF Interface Designed for RC2014.pdf
IDE Interface PCB.jpg

Bill Shen

unread,
Nov 27, 2018, 11:24:10 PM11/27/18
to RC2014-Z80
I've done data buffering with 82C55 as well as 74LS245.  They worked reasonably well, but not perfect.  In fact, no better than resistor termination and RC filter.  I tried again tonight, but implement the equivalent data buffer and I/O address decoder in a CPLD.  It worked roughly as well as resistor termination, but still can't deal with the Sandisk 256 meg (the one in the picture) and other CF disks that resistor termination failed on.
  Bill
DSC_40561127.jpg

Marten Feldtmann

unread,
Nov 28, 2018, 3:20:43 AM11/28/18
to RC2014-Z80
I would be interested to know, what goes wrong there (timing problems, noise, hard specifications) ..

Marten

Greg Holdren

unread,
Nov 28, 2018, 12:26:44 PM11/28/18
to RC2014-Z80
My guess is excessive ringing on rising/falling edge of the signals which is what series termination fixes. A probe of the signal with a scope would be interesting to see.

Greg

Mark T

unread,
Nov 28, 2018, 12:41:44 PM11/28/18
to RC2014-Z80
Or it could be data hold time, resistors or buffer could delay the data hold time slightly. The Z80 doesn't give much margin between data valid and /WR inactive.

I wouldn't expect that to be a problem with the 82C55 but there may be some other issue with those cards. Possibly no support for 8 bit mode.

Mark

Bill Shen

unread,
Dec 7, 2018, 12:54:39 PM12/7/18
to RC2014-Z80
This is rev1 of ZZ80RC.  The enhancement is the addition of compact flash interface and replacing the super capacitor with a CR1220 battery which should retain the RAM contents for over 1 year.  The CF I/O address is hardwired to RC2014's default 0x10 to 0x17.  This is a hobbyist-friendly design such that components are either through-hole or surface mount with wide spacing.  The base pc board is 100mm x 50mm, but with the addition of CF adapter and CF drive, the overall length is 155mm x 50mm.  CP/M 2.2 and CP/M 3 have been successfully ported to this design.
  Bill

DSC_40721207.jpg
DSC_40731207.jpg

Greg Holdren

unread,
Dec 7, 2018, 5:57:24 PM12/7/18
to RC2014-Z80

Bill,

This may not be directly related to the ZZ80RC but I was curious as to what software/technique you used to created the downloadable A: drive CPM disk?
I would like to add/delete files and make new images with files I use regularly on my Rev 0 board.

Thanks,
Greg

Bill Shen

unread,
Dec 7, 2018, 8:43:04 PM12/7/18
to RC2014-Z80
It is somewhat complicated process and I've only done it once so I have to think a bit to remember how I did it...please ask me to clarify if any part of my answers is not clear.

The usual process is use Grant Searle's FilePackage.exe in PC to assemble a hex package, XMODEM it across, and use depkg.com in CP/M to unpackage.  However the RAM drive on ZZ80RC is small, so there are no room to hold the hex package and run depkg.com.  What I did was (A) creating a disk image of drive A using cpmtools, (B) using BIN2HEX to create an extended linear addressing hex file of the disk image with correct offset, and (C) using a hex file loader that understands the extended linear addressing to load the file into memory.

In step (A), assuming you know how to cpmtools, the diskdefs you need is:
# RAM disk in ZZ80RC
# BLS of 2048
# 1024 sectors per track
# 256Kbyte of RAM
# 2 tracks
diskdef zz80rc
   seclen 128
   tracks 2
   sectrk 1024
   blocksize 2048
   maxdir 64
   skew 0
   boottrk 0
   os 2.2
end

In step (B), the RAMdisk A: image in memory starts from absolute address 0x10000, so the BIN2HEX command is:
BIN2HEX /O0x10000 /4 CPM22DRI.img CPM22DRI.HEX

In step (C), the "CPM22DRI.HEX" generated by BIN2HEX is loaded into ZZ80RC.  The hex file loader in ZZ80Mon does understand the extended linear addressing mode.
  Bill

Greg Holdren

unread,
Dec 8, 2018, 6:32:28 PM12/8/18
to RC2014-Z80

Bill,

Thanks for the explanation on the process. I have heard of cpmtools but never have use the package. I'll get familiar with cpmtools and see how far I can get with it.

Greg

Greg Holdren

unread,
Dec 8, 2018, 7:16:16 PM12/8/18
to RC2014-Z80
Since the initial disk is functioning, I wonder since there is a disk at 0x10000, if a section of disk can be moved in the 64KB region and read, converted to Intel hex and spit out on the console port for a term prog to log. Step through the whole disk region this way. Not sure if the Z280 can read more than 64KB at a time in Z80 mode or not. I'm guessing so since the whole SRAM has 19 address lines connected to it. Probably a MMU thing to deal with. This way A:/B: can be modified and saved out for next time the system needs refreshing. Different images could be loaded back depending on the task at hand.

Greg

Bill Shen

unread,
Dec 8, 2018, 9:08:59 PM12/8/18
to RC2014-Z80
There is already a "L" command in ZZMon that list memory content as Intel Hex.  In fact, that is how I save & restore BASIC program in SCMonitor's BASIC Ver 4.7b.  A special edition of SCMonitor with Startrek included is created by dump program + data from 0x0 to 0x9000.  The "L" command can be extended to the entire Z280 memory space, including the two RAMdisk.  This is a good way to save and restore RAMdisk contents.

Regarding cpmtools, this is the command I use to create a ZZ80RC image in a DOS window:

mkfs.cpm -f zz80rc cpm22dri.img

I then run a batch file to copy file into the image:

cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/asm.com 0:asm.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/bios.asm 0:bios.asm
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/cbios.asm 0:cbios.asm
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/ddt.com 0:ddt.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/deblock.asm 0:deblock.asm
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/diskdef.lib 0:diskdef.lib
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/dump.com 0:dump.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/dump.asm 0:dump.asm
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/ed.com 0:ed.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/load.com 0:load.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/movcpm.com 0:movcpm.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/pip.com 0:pip.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/stat.com 0:stat.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/submit.com 0:submit.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/sysgen.com 0:sysgen.com
cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/xsub.com 0:xsub.com


At this point you have the RAM disk image in binary form ready for BIN2HEX.

  Bill

Greg Holdren

unread,
Dec 9, 2018, 4:39:47 PM12/9/18
to RC2014-Z80
Bill,

Thanks for the additional information on the cpmtools. This got me going quick to make and test a disk image just fine. Now I'm trying to extend this to add files to the B: drive too. I tried something like:

cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/asm.com 1:asm.com

Note the "1". Didn't work out. Will look into it more as I haven't looked at the docs extensively yet.

You mention extending the "L" command to cover a bigger range i.e. where the disk drive memory is. It seems that the "L" command is only taking a max of 4 hex digits for the start and stop. Is this for the ZZMon or the SCMonitor?

Greg

Bill Shen

unread,
Dec 9, 2018, 5:33:28 PM12/9/18
to RC2014-Z80
Greg,


cpmcp -f zz80rc cpm22dri.img cpm22dri_ramdsk/asm.com 1:asm.com

The 1:asm.com indicates the file is accessible by user 1
so if you switched to "user 1", you should see the file "asm.com"

The starting address of RAMdrive B: is at 0x40000, so to load the image to drive B, relocate the image to 0x40000.  Another word:

BIN2HEX /O0x40000 /4 cpm22dri.img cpm22B.hex

Now load cpm22B.hex and you'll find the files at drive B

The 'L' command is a ZZMon command, so it is something I need to change.  Basically, the address field will increase to 6 digits to cover 16 meg of memory space and I need to set up a buffer to DMA a block data from the requested physical address to the buffer and then convert it to Intel Hex format.  I'll work on it.
  Bill

Greg Holdren

unread,
Dec 11, 2018, 1:12:58 AM12/11/18
to RC2014-Z80
Great, Thanks for the help!

Greg
Reply all
Reply to author
Forward
0 new messages