Micro Code

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

New Audio Boards

March 24, 2019 — Michael Engel

Long time no post... lots of things have happened (more on this later) since last July. One of the positive results is that we have designed and built new boards for our Signal Processing course.

Like the previously used Keil MCB4300 boards, we use the LPC4357 (dual core Cortex M4 and M0) SoC as basis, here supported by 32 MB of SDRAM as well as NAND and NOR flash. Since we cannot handle BGA parts in-house, we created an adapter to use Waveshare's Open4357 board with our base board designed for the Cortex M3/LPC1778.

Sound is handled by the relatively ancient NXP UDA1380TT codec, as on the Keil board. This chip is discontinued since around the year 2006, so I had to obtain a number via a specialized IC broker. The advantage of using that codec is that we stay compatible with the Keil board and we can reuse our existing driver code. Strangely, Waveshare still sells add-on boards using the same codec chip (only in an LQFP instead of an SSOP package), so they either have some secret source for the chip or invested in a lifetime supply...

One other addition is the nice graphical OLED display that you can see in the picture.

Signal processing board

Tags: audio, DSP, Cortex-M4, signal processing

PCB Art

July 20, 2018 — Michael Engel

I just dug out an old Sparcstation 20 mainboard from my collection, since someone on Usenet was looking for a spare one to fix his broken machine.

Taking a closer look at the board, I found this little sketch of a bear with a top hat. I have worked with Sparc machines for more than 25 years now, but never noticed that little guy before. Neat!

Bear on board

Tags: sparc, sun, workstation, PCB art

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