Micro Code

Michael's blog about teaching, hardware, software and the things inbetween

More on Oberon

July 08, 2018 — Michael Engel

Reading the Oberon source code, I got the impression that in a large number of places "magic numbers" are used without much explanation (neither in the code nor in the accompanying book).

One thing that had me wondering was the bitmap graphics generation. The Verilog source code (in VID.v) is quite simple. It uses a combination of simple counters to generate a 1024x768 pixel monochrome display. Based on a pixel clock counter, separate counters for the current horizontal (hcnt) and vertical (vcnt) coordinate are derived.

The video memory is addressed in 32-bit chunks, so each video line uses 1024/32 = 32 32-bit words (=128 bytes). The horizonal pixel counter is not 10 bits wide (counting 0..1023), but 11 bits, since it also counts the horizontal traceback time.

From the (10 bit) pixel position in hcnt, a 5 bit word offset in the current line is derived by cutting away the 5 least significant bits:

reg [10:0] hcnt;
reg [4:0] hword;  // from hcnt, but latched in the clk domain

always @(posedge clk) begin  // CPU (SRAM) clock domain
  hword <= hcnt[9:5];
end

If one wants to figure out which set of pixels is at what absolute memory address in SRAM, one stumbles across some strange things in the code:

localparam Org = 18'b1101_1111_1111_0000_00;  // DFF00: adr of vcnt=1023
assign vidadr = Org + {3'b0, ~vcnt, hword};

The binary constant in the Verilog code omits the two least significant bits of the address, since the 1 MB memory of the Oberon FPGA system is 32-bit word (4 byte) addressed; the address constant 0xDFF00 in hex gives the byte address of the frame buffer.

The display driver code in Display.Mod, however, gives a different frame buffer start address:

base = 0E7F00H;  (*adr of 1024 x 768 pixel, monocolor display frame*)

There's something fishy... the base address in the Oberon driver and the one in the Verilog source code differ by 0xE7F00-0xDFF00 = 0x8000 = 32768 bytes. So, what is going on here?

Pixels are set using the following function:

PROCEDURE Dot*(col, x, y, mode: INTEGER);
  VAR a: INTEGER; u, s: SET;
BEGIN a := base + (x DIV 32)*4 + y*128;
  s := {x MOD 32}; SYSTEM.GET(a, u);
  IF mode = paint THEN SYSTEM.PUT(a, u + s)
  ELSIF mode = invert THEN SYSTEM.PUT(a, u / s)
  ELSE (*mode = replace*)
    IF col # black THEN SYSTEM.PUT(a, u + s) ELSE SYSTEM.PUT(a, u - s) END
  END
END Dot;

The address for a pixel at position (x,y) is calculated as base + (x div 32) * 4 + y * 128. This sounds reasonable - each line is 128 bytes (128 * 8 = 1024 pixel) wide, x div 32 gives the word address offset in the current line, which is multiplied by 4 to give the word's byte address.

Accordingly, the pixel at address (0,0) is contained in the word at address 0xE7F00. But the Verilog source code starts reading the video buffer at address 0xDFF00... or does it? Let's take a closer look:

assign vidadr = Org + {3'b0, ~vcnt, hword};

When calculating the video memory address, the vcnt counter is inverted. Thus, the pixel at position (0,0) is at memory address (trailing "00" added to give the byte address):

0xDFF00 + { 000 1_1111_1111_1 000_00 00 } = 0xDFF00 + 0x1FF80 = 0xFFE80

Wait, that's still not right - what was the start address in the Oberon source again?

base = 0E7F00H;  (*adr of 1024 x 768 pixel, monocolor display frame*)

That's 0xFFE80-0xE7F00 = 0x17F80 = 98176 (dec.) bytes from the start!

Hmmm, wait... that's vaguely familiar. The whole monochrome 1024x768 bitmap screen uses

1024 / 8 * 768 = 98304 bytes

and 98304-98176 = 128, the memory used by one line of pixels. This works out since we were calculating the address of the leftmost pixel in the line.

Maybe you have already figured out what is going on here... Oberon's graphics coordinate system starts in the lower left corner of the screen, whereas the monitor's coordinate system starts at the upper left corner (see Chapter 4 in Wirth's Oberon book). Thus, the line at Oberon's coordinate y = 0 is the 767th line in monitor coordinates. Accordingly, inverting the y line coordinate in the Verilog address calculation

assign vidadr = Org + {3'b0, ~vcnt, hword};

causes the vertical line counter to count backwards. Note that the x coordinates of Oberon and the monitor count from left to right, so hword is not inverted.

The final remaining question is why the video base address is different. This is now also rather easy to see. vcnt is a 10-bit counter, so it counts from 0...1023. The Oberon y coordinates only are valid up to 767, so the 767th Oberon line = 0th monitor video line is at address

767 = 10_1111_1111 (binary), inverted = 01_0000_0000
0xDFF00 + { 000 0_1000_0000_0 000_00 00 } = 0xDFF00 + 0x08000 = 0xE7F00

Voila, there's the video memory start address that's defined in the Oberon driver source code.

If you take a closer look at the Draw function, you might now wonder what will happen if you pass a y coordinate larger than 767 to the Draw function. More on this in an upcoming blog post...

Tags: FPGA, Oberon, Xilinx, Wirth, graphics

More things from the dark corners of the lab cupboard

July 06, 2018 — Michael Engel

This is a MOS 6581 IC, the famous SID sound chip used in the Commodore 64 computer. Unfortunately, the "def." marking seems to indicate that it is defective. I'll have to test this...

MOS 6581 SID chip

Tags: MOS, 6581, SID, Commodore, C64, retrocomputing

Small is beautiful!

June 30, 2018 — Michael Engel

If you got into contact with computers in the 1980s (at least in Europe), there's a good chance that you have learned to program in Pascal, one of the languages designed by Prof. Niklaus Wirth at ETH Zürich.

Even though he is retired for several years now, to this day Prof. Wirth continues to design software and even hardware systems that follow the maxime "small is beautiful" - elegant and simple systems including more recent programming languages such as Modula-2 and Oberon, the whole Oberon system environment including a simple OS and a graphical user interface, and even complete computer systems. In-house designs at ETH were the early Lilith and Ceres workstations in the 1980s; more recently, Prof. Wirth designed a small RISC system on an FPGA including all peripherals that is able to run Oberon.

You can find more information on the Oberon system including all software and Verilog source code as well as a textbook describing the complete design at Project Oberon. Reading the sources is a nice project for a rainy weekend - the whole Oberon system's source code, including the compiler and GUI, is only about 10k LoC (written in Oberon, of course). The Verilog sources including the CPU, all peripheral interfaces and the video driver, amount to less than 1000 lines - impressive!

The Oberon FPGA system originally ran on a quite old FPGA board, the Xilinx Spartan 3 starter board, which features a Spartan 3S400, a tiny (by today's standards) FPGA, 1 MB of fast 32-bit SRAM, and a number of peripheral interfaces. I recently found my old Spartan 3 board and finally got the system to run.

Oberon on FPGA

In order to use the Oberon system, you have to connect a PS/2 keyboard and VGA monitor to the onboard ports. In addition, you need to connect an SD card (containing the Oberon file system image) and a PS/2 mouse.

For reference (you need to look it up in the ucf pinout definition file and figure out that SPI0 is the one the SD card is supposed to be connected to - SPI1 is reserved for some wireless network interface), here are the necessary connections to connector A2 on the board:

  • SD MISO: A2 pin 17
  • SD MOSI: A2 pin 7
  • SD SCLK: A2 pin 13
  • SD SSEL: A2 pin 5
  • SD Vcc (3.3V): A2 pin 3
  • PS/2 CLK: A2 pin 4
  • PS/2 DAT: A2 pin 6
  • PS/2 Vcc (5V): A2 pin 2
  • GND: A2 pin 1

I have used a generic Logitech PS/2 mouse (type M-BJ69) and a Waveshare Micro-SD adapter board with a SanDisk 8 GB card.

Tags: FPGA, Oberon, Xilinx, Wirth

It was twenty years ago tonight...

February 16, 2018 — Michael Engel

More looking through backups (what else would you want to do when it's -8 degrees outside?)... and another pictures folder, this time from 1998!

Back then, Linux was still a (rather) new and hot thing (and without systemd!). So, our Unix user group at Siegen Uni organised some events to gain more publicity for it. Our so-called "Linux Meetings" attracted up to 500 visitors over two days on a weekend.

So, here's a picture of yours truly from Linux Meeting 1998 in Siegen and some other impressions from twenty years ago... the shirt reads "Instant programmer... just add coffee", btw.

Me in 1998 Me in 1998 LM 1998 Big Tux LM 1998 plushies LM 1998 hackers LM 1998 impression LM 1998 sign

Tags: Unix-AG, Linux-Meeting, Siegen

Another blast from the past

January 21, 2018 — Michael Engel

While looking through some old backups, I came across a pictures folder dating from 2006. So, here's a picture of my office at TU Chemnitz, where I spent a year as acting professor for operating systems in 2006/07.

Nowadays, my colleague Matthias Werner occupies this office...

Chemnitz office

Tags: chemnitz, professor, office

Excursion Report Part 3: The Zuse Z23

January 01, 2018 — Michael Engel

The third part of our excursion to Erlangen was centered around the Zuse Z23 machine, which I already described in a previous blog entry about the Long Night of Science I attended some months ago.

Again, the demonstration of the machine was simply great - once more, thanks a lot to Volkmar and Edwin for hosting us!

So, here are some more impressions of the Z23 (original size photos available on request). All pictures are licensed under the Creative Commons CC BY-SA 4.0 license.

The machine and its operator

Z23 total

The computer itself

Z23 computer

Core memory modules

Z23 core memory

Hand-wired backplane

Z23 backplane

Close-up of some Z23 modules

Z23 module close-up

A page of the Z23 schematics

Z23 schematic

The magnetic drum unit

Z23 magnetic drum

Close-up of the drum read-write heads

Z23 drum heads

The magnetics of the drum itself

Z23 drum

Close-up of the head driver electronics

Z23 amplifiers

Tags: Zuse, Z23, FAU, RRZE, Erlangen, Excursion

Tiny Unix on a tiny microcontroller

January 01, 2018 — Michael Engel

There is one quite nice thing I (re)discovered over the Christmas break. At a MIPS FPGA workshop in Munich last January, I was given a ChipKit Wi-Fire board. This board is based on a Microchip PIC32MZ microcontroller, which includes a MIPS M14k CPU core with MMU and FPU, 2 MB of flash memory, 512 kB RAM and a number of peripherals.

This board is not only capable of running typical embedded operating systems, but is probably one of the tiniest platforms capable of running real Unix - namely the last BSD Unix version from UC Berkeley, 4.4BSD-Lite2. This final version from the CSRG research group came out in 1995 after a lengthy litigation in which AT&T (back then the owner of Unix copyrights) tried to hinder the publication of the BSD source code due to allegations of illegaly copied AT&T proprietary source code - luckily, this trial resulted in only six files which had to be removed from the BSD source code base; the 4.4BSD source code without the infringing files was then published as 4.4BSD-Lite2 and formed the basis for subsequent open source BSD projects, including 386BSD, FreeBSD, NetBSD, OpenBSD and DragonFly BSD.

Serge Vakulenko has worked on liteBSD, a port of 4.4BSD-Lite2 to the PIC32MZ MIPS-based microcontrollers for a number of years and managed to get it to work with the rather puny hardware resources of that controller (the MIPS architecture itself was supported by 4.4BSD in DECstation and SONY MIPS machines).

I got it to run on the Wi-Fire board (which is one of the boards supported out of the box by LiteBSD); it is quite an impressive achievement and, despite the minimal hardware resources, feels familiar to people used to modern Unix or Linux systems.

So far, I have fixed two bugs in the litebsd kernel source.

One was missing support for the execution of so-called shebang interpreted executables, i.e. shell scripts or similar (Perl, Python, awk, etc.), which start with the characted sequence "#!" followed by the name of the interpreter, such as "#!/bin/sh".

The other was a bug in the memory allocation code for ktrace, which resulted in a kernel panic during execution tracing when tracing was enabled in the kernel.

There is also RetroBSD, an even smaller version of BSD for very tiny microcontrollers, derived from the last PDP11 BSD Unix version, 2.11BSD.

Some links:

Wi-Fire board litebsd screen shot

Tags: mips, pic32, BSD, unix, litebsd

Teaching Award

January 01, 2018 — Michael Engel

There are some things which I need to catch up on, since the last few weeks did not leave much time for blogging.

First, a very gratifying and unexpected event - I was awarded the University of Coburg Teaching Excellence Award for the academic year 2016/17 after only one year of teaching there. This was quite unexpected and I am very proud and happy to have received this appreciation of my work here.

The physical manifestation of the teaching award, as shown below, is a glass plate etched with a picture of Friedrich Streib, who was the founder of the predecessor institution of Coburg University in the 19th century. Quite nice and original!

Btw., this is my second teaching award. The first one was the so-called Lehrer-Lämpel-Pokel (Teacher Lämpel trophy, named after a characted in the Max and Moritz illustrated verse stories by Wilhelm Busch) in the summer term 2015 at TU Dortmund, Department of Computer Science, for my course on computer architecture.

Teaching award

Tags: teaching, award, 2017