Giter VIP home page Giter VIP logo

smalltalk's Introduction

Smalltalk-80

Screenshot

Welcome to my "by the Bluebook" C++ implementation of the Smalltalk-80 system that runs on OS X, Windows, Linux, OpenBSD, and FreeBSD! Since first reading about Smalltalk in the August 1981 issue of Byte magazine, I have always been intrigued by it. At that time all we had were slow 8-bit computers with 4K of RAM barely running fast enough to do anything useful. I was stunned as I read through the article -- this was futuristic alien technology that was surely beyond my reach. In 1988, while attending the University of Washington, I was exposed to two memorable pieces of technology: The first was Steve Job's NeXTCube and the other was a Tektronix 4404 workstation running Smalltalk-80. Both were, and still are, amazing. It was only fitting that I implemented this Smalltalk on a descendent of the NeXTCube -- a MacBook Pro laptop.

In the late 90s, I discovered that my heroes from Xerox PARC got the "band back together" and released Squeak. I was thrilled to finally have a nice system to play with. But, I didn't care for the look and feel and missed the minimalism I had experienced on the Tektronix system. I also had a copy of the Bluebook and Greenbook and always daydreamed about making my own implementation, but I had no access to the porting kit that was used. That changed a few years ago when I found Mario Wolczko's website: http://www.wolczko.com/st80/ He had the Xerox release 2 virtual image (from magnetic tape) as well as the instruction manual and hand-typed smalltalk sources from the Bluebook! He also had his implementation, which was written in pre-ANSI C. But, despite many hours, I was not able to get anything to run. I then started to consider making my own implementation.

I knew this wouldn't be an easy task, as there would undoubtedly be errors in the book (there were). I also knew that C++ likes to index arrays starting from zero whereas Smalltalk starts at 1, so surely there would be off-by-one errors (there were). Smalltalk has a different operator precedence than C/C++, so I was on guard about that as well (to their credit, with a few exceptions, the expressions were parenthesized in a way where that wasn't an issue). Then there is reference counting being used, so there would probably be reference counting errors too (there were) and finally memory was a bunch of 16-bit words so you could accidentally store/fetch the wrong thing without realizing it. To top it off, the Alto is a big-endian system so I had to decide what to do about that (I byte swapped the virtual image as recommended by the Xerox guide -- their guidance was solid, but they missed the need to byte swap floats).

I started working on this in late December of 2019, but didn't really focus on it for a few months until the Corona virus struck and I decided to "quarantine myself" so as not to vector the virus to someone else. I then worked in earnest on it. The Xerox porting kit included reference "trace files" you could compare against your system. I felt an incredible rush when I passed trace2. After that the system ran a little while longer, and ran out of memory. I had no idea what was going on (this is before I had the display stuff working). To gain visibility, I intercepted and logged message sends using the show: and error: selectors as well as big-looking strings being pushed on the stack. Sure enough there was a traceback string that would have been displayed by the smalltalk debugger had only it made it that far. But, I was able to figure where I screwed up and then felt another rush when the screen was drawn into a Form I was able to dump to a .pbm file and see! After that I implemented the host graphical support for Smalltalk using SDL and implemented the input primitives so I had a working mouse and keyboard. I was finally able to really use the system. At that point, the system helped me find other issues! The graphical Smalltalk inspector and debugger really did the heavy lifting for me and saved me countless hours. The resiliency of the system is amazing.

But... since no file system support was available (the system image used the Alto file system classes), I could only see decompiled code in the source browser (which is still very useful and you could edit that -- it just didn't show temporary names you actually used and you lose your comments). Well, I had to decide what to do about that. Should I try to emulate the Alto file system? I decided against that and followed the approach used by Tektronix in the Greenbook -- I subclassed FileDirectory, File, and Page and created PosixFileDirectory, PosixFile, and PosixPage. I fired up VSCode and wrote an implementation for them that I could copy and paste into my Smalltalk (I added a way to paste characters from the clipboard into the input queue). After I had those implemented, I tested them, and once I was satisfied, I created the SourceFiles array with file streams for Smalltalk-80.sources and Smalltalk-80.changes. Once I did that --the instant I assigned that variable -- the magic happened. BANG! All of a sudden I could browse real source code in the browser! Now that I had a working file system, I re-pasted my implementation which was then stored by the system (to the changes file) and I could finally see my implementation with real temporary names and comments! It was the very delightful bootstrapping experience that makes you grin from ear to ear. I then did Smalltalk condenseChanges and saved the image. After I got it working on OS X, I moved it over to Windows in under an hour and also got it running under Linux in 15 minutes (for Linux, I tested it in a VirtualBox without graphics acceleration and the performance was bad -- hopefully on a "real" Linux machine it performs better).

Is the system usable? YES! You will definitely be constrained by the size of the object table, but you can still do stuff. I have to admit that I prefer the spartan look of Smalltalk-80 vs Pharo and Squeak (even though they are far superior).

There's a lot more to tell, but that's the gist of it. It was fun to do, and I'm glad that after all these years I was able to make it happen. I am still amazed by what the geniuses at PARC did. To think that amazing system I read about in 1981 was almost ten years old at the time of publication is mind boggling.

Using Smalltalk

Smalltalk-80 uses a three button mouse labeled Red (the left mouse button), Yellow (the middle), and Blue (the right button). The Red button is for clicking and selection. The Yellow is for running commands like "doit" and the Blue for things like closing a window. If you have a three button mouse you can use the -three command line option to use the traditional mapping. If you do not have a three button mouse, you can use the alternate (and default) mapping:

Two button mouse mapping

Button Mapping
Left Button Maps to Red button (selection)
Right Button Maps to Yellow button (doit)
Alt+Left Maps to blue button (close). On the Macintosh, this is Command+Left

Note: Ctrl+Left Button can also be used as the "yellow button."

The nice thing about building things by the book is there are books to document how to use the system and how it works!

Arrow Notation

Assignment in Smalltalk is made using the left-arrow which is written with shift -(_), the vertical-arrow is entered with shift 6(^).

Building and running

OS X

You will need to install SDL 2.0.12 or later. You can download it from http://libsdl.org. Choose the development library .dmg and install. Then, go into the osx folder and type: make -f MakefileRT

If you installed SDL2 through a package manager, or built it yourself, so your system has sdl-config in your path you can simply do: make You should then be able to do:

./Smalltalk -directory ../files

See the command line options section below for what this means. There is an xcode project you can open if you like.

Windows

I have included the SDL 2.0.12 headers/binary so all you need to do is open the project in the windows directory and hit Run.

Linux

You need to install SDL 2.0.12 or later. You can either go to http://libsdl.org and download and build it yourself or use a package manager to install it.

Then, cd into the linux subdirectory of this project and type make. You should then be able to do:

./Smalltalk -directory ../files

See the command line options section below for what this means.

OpenBSD and FreeBSD

The process is much the same for OpenBSD and FreeBSD as it is for Linux, except cd into the bsd subdirectory instead.

Configuration options

The behavior of the Smalltalk application can be customized through #define settings in the header file for each module.

Object Memory (objmemory.h) #defines

The Object Memory #defines determines the garbage collection scheme to be used (all the approaches described in the Bluebook are available).

Define Meaning
GC_MARK_SWEEP Use Mark and Sweep garbage collection
GC_REF_COUNT Use the reference counting scheme
RUNTIME_CHECKING Include runtime checks for memory accesses
RECURSIVE_MARKING The book describes a recursive marking algorithm that is simple, but consumes stack space. If this symbol is defined, that algorithm is used. If not the more complicated, and clever, pointer reversal approach is used instead.

The GC_MARK_SWEEP and GC_REF_COUNT flags are not mutually exclusive. If both are defined (and they are), normal reference counting will be performed, with full garbage collection only when memory is exhausted or the object table becomes full. Smalltalk-80 generates a lot of cyclical references (e.g. a MethodContext references, through a temporary field, a BlockContext that back references the context through the sender field). A Mark and Sweep only approach will result in many frequent collections as the object table will quickly fill with MethodContexts and other frequently allocated objects as the system runs. Some Smalltalk implementations recycle contexts for this reason.

Interpreter (interpreter.h) #defines

The interpreter #defines are provided to allow the inclusion/exclusion of optional primitives as well as a handful of helpful debugging methods. If an optional primitive is not implemented, a Smalltalk fall-back is executed instead. This can have a significant effect on performance.

Define Meaning
DEBUGGING_SUPPORT Adds some additional methods for debugging support
IMPLEMENT_PRIMITIVE_NEXT Implement the optional primitiveNext primitive
IMPLEMENT_PRIMITIVE_AT_END Implement the optional primitiveAtEnd primitive
IMPLEMENT_PRIMITIVE_NEXT_PUT Implement the optional primitiveNextPut primitive
IMPLEMENT_PRIMITIVE_SCANCHARS Implement the optional primitiveScanCharacters primitive

Application (main.cpp) #defines

When running under Windows I ran into two problems. First, the mouse cursor wouldn't reliably change if the left mouse button was being held down (e.g. when reframing a window). The second issue was that the mouse cursor was very small on high resolution displays, even when system scaling options were set to compensate for it. For these reasons, I added the option to have the app render the mouse cursor rather than the operating system. The SOFTWARE_MOUSE_CURSOR can be defined to do this. I set this conditionally if it's a Windows build. It works on the other platforms, but is unnecessary as they behave properly without it.

Command line arguments

The Smalltalk application takes a number of arguments. The only required argument is -directory path which specifies the directory where the snapshot image can be found. Here is the complete list:

Argument Meaning Default
-directory path Specifies the directory that contains the snapshot image, as well as the Smalltalk-80.sources and Smalltalk-80.changes files. Any other files in the directory will be accessible from Smalltalk-80 using the normal file/directory access methods. required
-three Use the three button mapping two button scheme
-image Name of the snapshot file to use. snapshot.im
-cycles Number of VM instructions to run per update loop 1800
-vsync Turn on vertical sync for synchronizing the frame rate with the monitor refresh rate. This can eliminate screen tearing and other artifacts, at the cost of some input latency. off
-delay ms if vsync is not used a delay can be specified after presenting the next frame to the GPU. This is useful for lowering the CPU usage while still enjoying the benefits of not using vsync 0
-2x Specifies that the display should be doubled. Helpful for farsighted folks, or people running on very high resolution displays off

smalltalk's People

Contributors

dbanay avatar fogus avatar gamecubate avatar jakembauer avatar neauoire avatar wardcunningham avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

smalltalk's Issues

Kudos

This is really neat.

Launched like a charm on macOS once this, in osx/Makefile:

SDL_CFLAG := $(shell sdl2-config --cflags)

was replaced by that:

SDL_CFLAG := $(shell sdl2-config --cflags | sed 's/\/SDL2//')

Thanks!

Installation instructions for Linux needs adjustements

Hi Dan,

First of all what a fantastic job you have done. Really! I always dreamt of running the original ST-80 images again.... You made my deram come true.

One minor adjustement in the installation instructions for Linux. Here is what I did:

$ git clone repo
$ cd Smalltalk
$ ./configure
-bash: ./configure: No such file or directory
$ cd linux
$ make
$ make install
make: *** No rule to make target 'install'.  Stop.
$ ./Smalltalk 

it opens Smalltalk 80 just fine!! Yeah...

So in other words I could not run ./configure, nor make install on Linux.

Besides on my Debian distro you can also simply install the SDL 2 dev package and it works fine
$ sudo apt install libsdl2-dev

Bit of a hint for MacOS compilation

Not really an issue, but I had some struggles last night with building this for MacOS so I thought I'd let you know in case you wanted to update the documentation. I'm terrible at C++ so it may well have been my fault.

The Makefile was using sdl2-config --cflags to add -L/opt/homebrew/include/SDL2 to the include path. This wasn't working - I'm assuming because #include "SDL2/SDL.h" was trying to look for an SDL2 directory inside SDL2. I changed the flag to -L/opt/homebrew/include and it compiled and ran just fine.

As I say, might just be me doing something else wrong 🤷.

Really looking forward to going through the blue and red books using this - thank you so much!

Eating all CPU

Hi Dan,

I also noticed that once Smalltalk is running it keeps eating almost 100% of the CPU. I guess there must be some kind of event polling loop running forever, right ?

Question about snapshot code hitting asserts :-)

Hi Dan,

This is most assuredly not an issue with this codebase but seemed like a decent way to get in touch. I've been working with a friend on trying to implement a blue book Smalltalk in C for the Amiga computer. I confess I have joined the project late and have been cargo-culting a bit over there and occasionally looking to your excellent project for a clue when I get confused. I recently started working on a way to load and save an image (we have a mostly functional ObjectMemory but no interpreter really yet). I've pretty much been trying to work from your code and I think I have it basically working - loading and saving the ST80 image you linked to.

One question I have though... I hit the assert ( https://github.com/dbanay/Smalltalk/blob/master/src/objmemory.cpp#L119 ) that's designed to stop a zero-counted object being loaded, and I hit it a few times. If I disable that assert and just load the image anyway, it all seems to work fine (as I say, no interpreter, so all I can really say is we end up with a basically intact ObjectMemory).

Screenshot 2020-12-23 at 21 44 28

So I guess my question is if you load that tape image with your code, I'm puzzled why the assert doesn't fire and I wonder if I've done something wrong somewhere. 🤔

Thanks for your time,

Alan

Having trouble with BitBlt::RightMasks at link time

I presume this is some fistfight regarding constexpr and someone is confused if it is resolved at compile time vs. needs to be resolved. I'll mess with it and see if I can figure it out.

~/Source/OpenSource/Smalltalk/osx$ gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
~/Source/OpenSource/Smalltalk/osx$ make
g++  -O3 -std=c++14 -c ../src/objmemory.cpp  -o objmemory.o
g++  -O3 -std=c++14 -c ../src/bitblt.cpp  -o bitblt.o
g++  -O3 -std=c++14 -I/Library/Frameworks/SDL2.framework/Headers -F/Library/Frameworks   -c ../src/main.cpp
g++  -O3 -std=c++14 -c ../src/interpreter.cpp  -o interpreter.o
g++  -F/Library/Frameworks -framework SDL2  -o Smalltalk  objmemory.o bitblt.o main.o interpreter.o
Undefined symbols for architecture x86_64:
  "BitBlt::RightMasks", referenced from:
      BitBlt::computeMasks() in bitblt.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Smalltalk] Error 1

Unable to compile under Fedora 28

I checked I had SDL2-devel installed, I do.

bash$ rpm -qa | grep SDL
...
SDL2-devel-2.0.9-1.fc28.x86_64 <<< I think I done something bad....>>>
...
I suspect I missed something in the Readme.txt (I did).

I grabbed the most recent revision I could find of Smalltalk here: 8fc5c39
bash:/home/viking/src/smalltalk/ST80 $ git clone https://github.com/dbanay/Smalltalk
...

I tried retrieving the current revision from git:
bash:/home/viking/src/smalltalk/ST80/Smalltalk $ git describe
fatal: no names found, cannot describe anything

I then tried to make the project:
bash:/home/viking/src/smalltalk/ST80/Smalltalk/linux $ make
g++ -std=c++17 -O3 -c ../src/objmemory.cpp -o objmemory.o
g++ -std=c++17 -O3 -c ../src/bitblt.cpp -o bitblt.o
g++ -std=c++17 -O3 -c ../src/main.cpp
../src/main.cpp:58:14: error: 'SDL_PixelFormatEnum' does not name a type; did you mean 'SDL_PixelFormat'?
static const SDL_PixelFormatEnum TextureFormat = SDL_PIXELFORMAT_RGB565;
                                 ^~~~~~~~~~~~~~~~~~~
                                 SDL_PixelFormat
../src/main.cpp: In member function 'virtual bool VirtualMachine::set_display_size(int, int)':
../src/main.cpp:374:51: error: 'TextureFormat' was not declared in this scope
         texture = SDL_CreateTexture(renderer, TextureFormat, SDL_TEXTUREACCESS_STREAMING, display_width, display_height);
                                               ^~~~~~~~~~~~~
../src/main.cpp:374:51: note: suggested alternative: 'SDL_FreeFormat'
         texture = SDL_CreateTexture(renderer, TextureFormat, SDL_TEXTUREACCESS_STREAMING, display_width, display_height);
                                               ^~~~~~~~~~~~~
                                               SDL_FreeFormat
make: *** [Makefile:11: main.o] Error 1
bash$

So, where do I go from here? I don't really have the ability to upgrade my Fedora to the latest version at the moment.

Regards, brickviking

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.