[GreenKeys] Mini Makefest in Manchester UK England

Dave G4UGM dave.g4ugm at gmail.com
Wed Aug 5 05:29:54 EDT 2015


I am sorry to say my SSEM emulator , the "extremely small scale experimental
system", or "baby baby" for short is written in VHDL and runs on a Nexys 3
Spartan 2 board. It can be seen here:-

https://www.youtube.com/watch?v=OGcAmrFoRrY

Very little original code survives. I think there are two programs, one
which is the first program they ran which I think calculates the HCF of
2**18, and to be honest I can't remember what the other is.

Also please note that Turing had, as far as we can tell,  nothing to do with
the Baby's design or construction. At the time the SSEM was complete he was
at NPI I believe, but came to Manchester soon after it was complete.

I will send you some more info about Baby programs off-list.

Dave

> -----Original Message-----
> From: GreenKeys [mailto:greenkeys-bounces at mailman.qth.net] On Behalf
> Of Dave Horsfall
> Sent: 05 August 2015 08:33
> To: Greenkeys <greenkeys at mailman.qth.net>
> Subject: Re: [GreenKeys] Mini Makefest in Manchester UK England
> 
> On Tue, 4 Aug 2015, Dave G4UGM wrote:
> 
> > I am, under the guise of the Manchester Vintage and Retro Computing
> > Club (which is basically me and a couple of other guys), will be
> > having a stand at the Mini MakeFest @ the Museum of Science and
> > Industry , Manchester England. We will be demonstrating RTTY Art under
> > the excuse that many early Manchester computers (Manchester Mk1,
> > Ferranti Pegasus and Mercury) used Creed Teleprinters as output devices.
> 
> Goodness gracious me!  I've just written an emulator of the SSEM (Small
> Scale Experimental Machine aka "Baby") which was the precursor to the Mk-
> I.
> 
> I was wondering where I could express a hope for some live binary code for
> the SSEM (not the Mk-I).  Someone (Turing?) wrote a program (via the
> switches alone) to compute the GCD, for example.
> 
> Oh, I took the easy approach and coded everything in Big-Endian; the Baby
> had Little for the opcodes and the addresses, but I'm willing to change
that.
> 
> Highly beta (it has an interrupt bug), and yes, I have a weird coding
style.
> 
> /*
>  * An implementation of the SSEM (Small Scale Experimental Machine aka
> Baby;
>  * the predecessor of the Manchester Mk I).
>  *
>  * At least one description is incorrect; it is described as the Mk I
>  * itself, which was a 40-bit machine, not 32-bit, and only had 32 words,
>  * not 8K.  Also index registers, multiply, etc...
>  *
>  * Flags (maybe):
>  *
>  *	-d	Debugging
>  *	-D	Interactive debugger i.e. console-like (or swap with above)
>  *	-m	Memory size (default 32, must be power of two)
>  *	-M N	Set memory to all N
>  *	-r N	Seed for random initialisation of memory (see later)
>  *	-q	No messages
>  *	-v	Verboser messages
>  *	-x	Extensions such as full 8KW, memory-mapped I/O, etc
>  *	-z	Run at original speed (approx 1 KiPS)
>  *
>  * An instruction has the following format:
>  *
>  *	31..16	Ignored
>  *	15..13	Opcode (seven ops, as two are decoded the same)
>  *	12..0	Address (presumably wrapped for 32 words)
>  *
>  * The instruction set is best described as "minimalist"...  Oh, and
>  * the addr/opcode bits are LSB -> MSB, but I'm ignoring that for now.
>  */
> 
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <sys/time.h>
> #include <signal.h>
> 
> #define	DEFMEM	32	// 32 words by default
> #define	MAXMEM	(1<<13)	// Cannot exceed this
> #define	IMASK	0xFFFF	// Instruction mask (before shift)
> #define	ISHFT	13	// Where the opcode is
> #define	OMASK	0x1F	// Operand mask (for 32 words)
> 
> /*
>  * Opcodes (such as they are).  Note that on the real SSEM they were
flipped.
>  */
> #define	JMP	0	// Jump Indirect to address-1
> #define	JRP	1	// Jump Relative to address-1
> #define	LDN	2	// Load Negative
> #define	STO	3	// Store
> #define	SUB	4	// Subtract
> #define	SUBx	5	// Same due to hardware decoding
> #define	CMP	6	// Compare and skip if -ve
> #define	STP	7	// Stop
> 
> void	intr();		// Called at SIGINT in case of loop
> void	dump_cpu();
> void	dump_mem();
> void	kips();		// How fast were we?
> void	load(char*);	// Load the code
> 
> uint*	mem;		// Memory
> ushort	pi;		// Present Instruction
> ushort	s;		// Operand address
> ushort	cr;		// Control Register i.e. program counter
> int	acc;		// Accumulator
> int	seed = 1;	// For randomly initialising memory etc (POSIX
> default)
> int	init = 0;	// Initial value for memory
> int	stopped = 0;	// Set by the STP opcode
> uint	memsz = DEFMEM;	// Size of memory
> uint	omask = OMASK;	// Operand mask
> long	cycles = 0;	// No. cycles executed
> struct timeval	then, now;	// For timing porpoises
> volatile sig_atomic_t interrupted = 0;	// Sigh...
> 
> char* opcodes[] = { "JMP", "JRP", "LDN", "STO", "SUB", "SUB", "CMP", "STP"
> };
> 
> void
> main(int argc, char** argv)
> {
>     int		i;
>     int		ch;
>     int		d_flag = 0;	// Debug
>     int		m_flag = 0;	// Memory size specified
>     int		M_flag = 0;	// Initialise memory to this
>     int		x_flag = 0;	// Extended mode
>     int		z_flag = 0;	// Snooze to emulate original speed
> 
>     // setlinebuf(stdout);
> 
>     while ((ch = getopt(argc, argv, "dm:M:r:xz")) != -1)
>     {
>     	switch (ch)
> 	{
> 	    case 'd':			// Debugging
> 		d_flag = 1;
> 		break;
> 
> 	    case 'm':
> 		m_flag = 1;		// Memory size
> 	    	memsz = atoi(optarg);	// It better be shiftable i.e.
2^N...
> 		if (memsz > MAXMEM)
> 		{
> 		    printf("Memory %u cannot exceed %d\n", memsz,
> MAXMEM);
> 		    exit(1);
> 		}
> 		if (memsz < DEFMEM)
> 		{
> 		    printf("Memory %u must be st least %d\n", memsz,
> DEFMEM);
> 		    exit(1);
> 		}
> 		omask = memsz - 1;
> 		break;
> 
> 	    case 'M':			// Initialise to this
> 	    	M_flag = 1;
> 		init = atoi(optarg);
> 		break;
> 
> 	    case 'r':			// Random seed
> 		seed = atoi(optarg);
> 		if (seed == 0)		// Pick one ourselves
> 		    seed = getpid() * time(NULL);
> 		break;
> 
> 	    case 'x':			// Extended mode (maybe)
> 	    	x_flag = 1;
> 		break;
> 
> 	    case 'z':			// Snooze to emulate real speed
> 	    	z_flag = 1;
> 		break;
> 
> 	    case '?':	// Needed?
> 	    default:
> 		printf("Bad flag\n");
> 		exit(-1);;
> 	}
>     }
> 
>     argc -= optind;
>     argc +- optind;
> 
>     if (argc != 1)
>     {
> 	printf("Usage: %s [flags] file\n", argv[0]);
> 	exit(1);
>     }
> 
>     if (x_flag && !m_flag)
> 	memsz = MAXMEM;
> 
>     if ((mem = (uint*)malloc(memsz)) == NULL)
>     {
> 	printf("Cannot alloc %u bytes of memory\n", memsz);
> 	exit(-1);
>     }
> 
>     signal(SIGINT, intr);	// So we can stop a loop
> 
>     // Assumptions...
>     cr = 0;
>     acc = 0;
> 
>     // Initialise memory (random for now; will be 0)
>     srand(seed);
>     for (i = 0; i < memsz; i++)
> 	mem[i] = M_flag? init : rand();
> 
>     load(argv[optind]);
> 
>     dump_mem();
> 
>     printf("\nCPU trace:\n\n");
> 
>     gettimeofday(&then, NULL);
> 
>     while (!stopped && !interrupted)
>     {
> 	cycles++;
> 	cr &= omask;			// Adjust program counter
> 	pi = (mem[cr] & IMASK) >> ISHFT;// Opcode
> 	s = mem[cr] & 0x1FFF;		// Operand address
> 
> 	dump_cpu();
> 
> 	switch (pi)
> 	{
> 	    case JMP:
> 		cr = mem[s & omask];
> 		break;
> 
> 	    case JRP:
> 		cr += mem[s & omask];
> 		break;
> 
> 	    case LDN:
> 		acc = -mem[s & omask];
> 		break;
> 
> 	    case STO:
> 		mem[s & omask] = acc;
> 		break;
> 
> 	    case SUB:
> 	    case SUBx:
> 		acc -= mem[s & omask];
> 		break;
> 
> 	    case CMP:
> 		if (acc < 0)
> 		    cr++;
> 		break;
> 
> 	    case STP:
> 		gettimeofday(&now, NULL);
> 		printf("\nStopped (%ld cycles):\n\n", cycles);
> 		stopped = 1;
> 		dump_cpu();
> 		printf("\n");
> 		dump_mem();
> 		kips();
> 		break;
> 	}
> 
> 	if (z_flag)
> 	    // usleep(1000);	// Adjust for 1.1 kIPS - 0.7
> 	    usleep(500);	// Adjust for 1.1 kIPS - 1.4
> 	cr++;
>     }
> 
>     if (interrupted)
>     {
> 	gettimeofday(&now, NULL);
> 	printf("\nInterrupted (%ld cycles)!\n\n", cycles);
> 	dump_cpu();
> 	printf("\n");
> 	dump_mem();
> 	kips();
> 	exit(-1);
>     }
> }
> 
> void
> intr()
> {
>     interrupted = 1;	// printf() ist verboten
> }
> 
> /*
>  * Print CPU state.
>  */
> void
> dump_cpu()
> {
>     cr &= omask;
>     printf("cr = %.4x -> %.8x, pi = %d (%s), s = %.4x, acc = %.8x (%d)\n",
> 	cr, mem[cr], pi, opcodes[pi], s, acc, acc); }
> 
> void
> dump_mem()
> {
>     int		i;
> 
>     printf("Memory dump (seed %.8x/%d/%u):\n", seed, seed, seed);
> 
>     // Do ASCII as well?
>     // And 8k means 1024 lines!
> 
>     for (i = 0; i < memsz; i++)
>     {
> 	if ((i % 8) == 0)
> 	    printf("\n%.4x: ", i);
> 	printf(" %.8x", mem[i]);
>     }
> 
>     printf("\n");
> }
> 
> /*
>  * Print the bogo-kips for fun.
>  */
> void
> kips()
> {
>     long	took;	// Milliseconds
> 
>     took = ((now.tv_sec-then.tv_sec)*1000) + (now.tv_usec-
> then.tv_usec)/1000;
>     if (took == 0)
> 	printf("\nSpeed of light!\n");
>     else
> 	printf("\n%.2f kIPS\n", (double)cycles/(double)took); }
> 
> /*
>  * Load the specified object file.
>  * The spec is highly fluid right now...
>  */
> void
> load(char* file)
> {
>     FILE*	f;
> 
>     if ((f = fopen(file, "r")) == NULL)
>     {
> 	perror(file);
> 	exit(1);
>     }
>     printf("Loading from %s\n", file);
>     fclose(f);
> }
> 
> --
> Dave Horsfall DTM (VK2KFU)  "Those who don't understand security will
> suffer."
> Watson never said: "I think there is a world market for maybe five
> computers."
> __________________________________________________________
> ____
> GreenKeys mailing list
> Home: http://mailman.qth.net/mailman/listinfo/greenkeys
> Help: http://mailman.qth.net/mmfaq.htm
> Post: mailto:GreenKeys at mailman.qth.net
> 
> 2002-to-present greenkeys archive:
> http://mailman.qth.net/pipermail/greenkeys/
> 1998-to-2001 greenkeys archive:
> http://mailman.qth.net/archive/greenkeys/greenkeys.html
> Randy Guttery's 2001-to-2009 GreenKeys Search Tool:
> http://comcents.com/tty/greenkeyssearch.html
> 
> This list hosted by: http://www.qsl.net
> Please help support this email list: http://www.qsl.net/donate.html



More information about the GreenKeys mailing list