This Old Server, Part 4: Finished!

Dell Server Case 2013-10-05 022

Following up from last time.  Here’s the new front panel mounted in the Dell case.  The ugly patched-up component on the right is a old USB front panel that has been much abused.  Part of it is taped off because it is an audio panel I don’t use and don’t have connections for in the server.  The other part is taped off because I snagged a thumbdrive in the port one day and the port broke off to save the drive!  The hard disks are already mounted in their cage.  On top is a Blu-Ray drive from my old server.  You may have seen a DLT drive in the old machine earlier in the series, I didn’t install it because it is SCSI and I have no card for it.  I also wish I could have saved the original PERC RAID card, but it does not fit.  Maybe eBay, someday.

Here’s another shot of the inside:

Dell Server Case 2013-10-05 015

At this point, the system is just about complete.  There are two USB connectors on the original Dell.  I’ve wired extensions to these with an old USB cable that I cut up for the purpose, so I have 4 USB ports up front.  The small card in the foreground is an external SATA controller that I use with my backup drives.

There are just a few loose ends.  I mentioned before that I used my old Tyan board to mark out holes to drill for standoffs.  The Supermicro is a mini-ATX board and some of the mounting holes did not line up.  The board is secure for now but I want to fix this by marking new holes and removing the board to drill new ones, so that all seven screws will secure the board.

I also have to work on the fans.  The Dell 1800 used two large (120mm) fans.  One was a case fan—it’s the black plastic casing on the bottom right;  the other fan mount can be seen on the top left.  This was originally part of a air shroud that cooled the CPU.  (Again, I forgot to take pictures, but most of Dell’s servers have elaborate shrouding and air flow management.)  I haven’t mounted that fan.  I’m wondering if a thin-profile 120mm fan would fit in the drive cage;  it does get hot in that area.

The Dell 4-pin fan wiring will work on a modern white-box server board, but the connectors aren’t compatible.  Also, these are big fans that draw 2.5A, much more than the 0.5-1A fans that most white-box boards have, so I don’t dare try running them directly from the motherboard.  I did get one fan working on plain 12V without tachometer control but it is loud so I disconnected it.  The Supermicro already ran much cooler than the Tyan, and even more so in the new, roomier case, so I’m not worried for the moment.

(Fun fact:  When I took the old Tyan board out of my old server case, it was still hot in my hands!)

My server, complete!  Notice the white LED for power:

White box in old Dell case

There used to be Intel Inside, but not anymore!

Inside my Dell PE 1800.  Now with a Supermicro H8SCM-F.

A case like this would have cost me well north of $200;  when I originally spec’d out my machine earlier this year, I was really worried that I’d have to house it in a cardboard box because suitable tower enclosures were either unobtainum or expensivum.

I may not be cut out for casemodding, but the results seem to be good enough.   Happy casemodding!

This Old Server, Part 3: Lighting it up!

Dell server case being tested

I’m writing about an old Dell 1800 server case that I have modified for a whitebox server.  Last time I talked about the old front panel, this is how I had to build a new one.

This is the Supermicro’s front panel connection pinout, similar to other white-box servers.  I did not use the NIC1, NIC2 or Power Fail LED connections

1 Power switch
2 Power switch GND
3 Reset switch
4 Reset switch GND
5 Vcc +5V
6 Power fail LED (not used)
7 Vcc +5V
8 Overheat/Fan fail LED
9 Vcc +5V
10 LAN NIC2 active (not used)
11 Vcc +5V
12 LAN NIC1 active (not used)
13 Vcc +5V
15 Vcc +5V
16 Power LED
17 Key (No connection)
18 Key (No connection)
19 NMI switch
20 GND

This is my completed board:

Old Dell Server Case 2013-10-01 002

I did a cheap and ugly thing for the connecting cable:  I used an old hard drive cable and cut off half the pins with a hacksaw, then used hot-melt glue to seal one end of the connector so it could plug into the motherboard without coming apart.

The original board had buttons for power, ID (identification) and NMI.  The ID feature is common to server boards and consists of a blinking light that is activated with a pushbutton, or remotely from SNMP systems management software.  My Supermicro does have a remote management board, but I could not find the equivalent function, so the ID button on the original board is now a reset button.

The NMI button is recessed on the Dell and it is common on servers, including white-box boards.  When pushed, the system asserts the NMI—Non-Maskable Interrupt—signal which will halt most systems.  Windows will bluescreen (with the appropriate registry changes), and provide a crash dump on this signal.  The Supermicro has an NMI input so this is perfect.

I put just three LED’s on the board:  Power, which is no longer blue (I broke the original LED when trying to salvage it) but now white, HD access (orange) and Overheat/Fan Fail (orange).

I preserved the original intrusion switch and connector, which runs to another connector on the Supermicro board.  I haven’t been able to find intrusion settings in the BIOS but I presume they are there, unless they are in the IPMI remote interface.

At this point, I had a functional system in my new case.  Next post is the finish, with a few loose ends and final thoughts.

This Old Server, Part 2: Drilling, Grinding and Wiring

Supermicro H8SCM-F in Dell 1800

Continuing from my last post, I have a “new” Dell 1800 server case, but I needed to adapt it to a white-box motherboard.  I had originally planned to buy the new motherboard after getting the case, but delays and SATV work compelled me to get the new motherboard running in the old, junky case while working on the Dell case.  This is my new Supermicro H8SCM-F server board, which is considerably smaller than the original Dell board.

I forgot to take photos of the grinding and drilling I had to do to this point, so I’ll have to describe it.  I used a cutoff wheel (and safety goggles!) to grind off the original I/O plate, and several of the standoffs.  I then drilled new holes, marking them off with my old Tyan motherboard as a template.  This was a lot of fun, well, not so much.  This was, after all, a “real” server case, so the steel baseplate is thicker than one sees on a white-box server case, particularly the cheap ones I have encountered.

Most white-box cases have a frame in the rear to hold the I/O plate.  The Dell doesn’t, as the I/O plate is part of the motherboard tray.  After much cursing, I used aluminum tape to secure the I/O plate, and I did get the tray and the board to fit inside the case securely.  I’ll need to rip off the tape if I change the motherboard.  That’s acceptable.

On to the front panel.  

Dell PE1800 front panel

There are three buttons on the board for POWER, ID and NMI, plus a socket which connects to an intrusion switch mounted on the lower front of the case.  There are two LEDs, one is a bicolor blue/orange that is used for power on and alert indications, respectively, and a blue LED that blinks when the ID button is pressed.  There is also an LM75 thermal sensor on the board.  Here’s the pinout as best as I could trace it, for posterity’s sake.  LED1 is the bicolor power/alert LED. Blank pins are either not used, or I could not determine their function.

Pin Function
1 +5 V
2 GND, LED 1 pin 2
3 NMI switch positive
5 ID switch positive, LED 1 pin 3
6 NMI switch negative
8 Intrusion switch, pin 3
9 Power switch positive
10 I2C clock, SN75
12 I2C data, SN75
13 Intrusion switch, pin 2

This is proprietary to Dell, and was not a match for my Supermicro.  It wasn’t feasible to modify the front panel for my motherboard, so I just cut an Adafruit breadboard down to the size of the original.

Dell front panel with Adafruit breadboard

More about the front panel, and finishing my server, in my next post.

This Old Server, Part 1: Too Hot

1998-era junky server case

I’ve written before (This Hot Server) about my home server, and the work I’d done to it.  The case, dating from 1998, was as junky as the parts it once housed.  This summer, we had another heat wave in Salem, and for the better part of July my apartment topped out around 95 degrees F!

Just about every electronic device I owned overheated and shut down in those several weeks, including my tablet!  One device of mine, a graphics card in my workstation, died after reaching 160 degrees.  Celsius. (!!!)  (Trackmania had been stuttering for a while, making gameplay miserable.  Now I knew why.  Of course my card’s fan used cheap sleeve bearings!  Of course was the fan not replaceable! Of course it was toast…!)

Amazingly, my server only shut down a few times!  The Tyan board I had was remarkably tolerant to the environmental abuse I put on it.  I wanted to get a new server board anyway, but more importantly I wanted a new case.

SATV had an old Dell server that was just about depreciated and I claimed it, after salvaging the hard drives for SATV’s use:

SATV's former Dell PowerEdge 1800

Dell systems—I have parted quite a few—tend to be almost physically compatible with ATX form factors.  But not quite.  Most of my server parts would fit in this case.  But, again, not quite.  There were some modifications needed, like the motherboard tray:

Dell PowerEdge 1800 motherboard tray

This motherboard tray would be a challenge.  First of all, most of the standoffs would need to be removed, and new threaded hex standoffs (the standard for white-box cases) would need to be drilled and installed.  The biggest problem was the I/O panel.  In most boards, the I/O panel is a cheap steel plate with holes for the specific I/O ports, serial, video, USB on the motherboard, and they are placed differently for each board.  The Dell’s I/O panel was thick steel, part of the motherboard tray itself.  I had never used a cutoff wheel with my old Dremel clone, but I was about to find out how.

I also had to figure out the front panel:

Dell PE1800 front panel

The power LED on this Dell glowed a nice bright blue when it was on, but the pinout of this panel is nothing like most white box servers I have seen, or owned.  Of course it wasn’t in the Dell service manual.

There were some promising signs.  The Dell power supply and its tray fit the standard EPS12V:

 Dell PE 1800 power tray, drive cage and fans

The PE1800 also came with a decent drive cage and two good fans.  We never had thermal problems with that machine for the 8 years it was in service.

More to come in Part 2.

Nice Homemade Retro Shirt

Homemade PDP/11-60 T-shirt

I wanted to put this online before I forgot about it.  I wore this shirt at SATV over the summer.

This past Christmas season, my brother gave me this gift.  It’s a homemade T-shirt transfer.  These are now good enough to give sports teams and licensed vendors fits, and I was surprised at how good these come out for my brother’s modest setup.

The image is of a DEC PDP-11/60 minicomputer similar to the one Salem High School had when I attended in the late ‘70s.

It’s true.  It did start for me then.

Thank you, Randy!

David Moisan’s IT Resumes Blogging

SATV's new Dell T320 server

It’s been a year since my last post, Hac-Man Won the Retrochallenge!  I’ve been very busy at SATV and with the Salem Commission on Disabilities.  SATV is coming up on our franchise renewal year;  the current contract runs out 11 months from now, in September 2014, and we started the planning process a year and a half ago.

My part of the process is to determine, for a 10 year contract cycle, what IT we need.  Keep in mind that it’s practically impossible to determine technology trends more than a few years out.  Rather than even try doing that, I just made estimations based on our current technology, our equipment refresh schedule (which varies by the technological area) and our unmet needs, pain points and so forth.

It was a very exhausting process that I can’t fully get into here, but let’s just say from September of last year until September this year, I and our executive director, had our heads down in this.  I also had to refresh our network server sooner than we had anticipated as our backup Dell 1800 server was 8 years old and showing ECC memory errors.  It was also the last 32-bit Windows server in the building long after Microsoft moved to 64-bit only server OS’s.  That machine had a good life.

Our newer Dell 1900 was running good, but it was also running SBS 2008.  As many readers know, there was a major disturbance in the SBS world last year. Microsoft discontinued SBS!  The operating system I had been certified on twice (SBS 2008 and SBS 2011) was dead.  SATV had been an SBS shop since the old BackOffice 4.0 days and I knew we would have to find a replacement head on.

I can’t get into any more detail about this either, but I like to quote an old phrase all the time, “The cobbler’s children go barefoot”.  Between SATV’s franchise preparations, my own research into a life without Small Business Server,  and numerous other personal circumstances, I had no energy for blogging or much of anything else.

I even missed the screaming about Windows 8.  I had tried the developer preview, so I knew it was going to be a very different experience,  but I had no time whatsoever to even try it out thereafterwards   I finally got to use it after all when I convinced SATV to get me a staff laptop with Win 8 on it.  (After using Win 8, oddly enough, I dislike Win 7 now.)

I also spent the past three months of summer and early fall migrating from SBS 2008, and Windows Server 2008, to a new server that is running Windows Server Essentials, Exchange and Sharepoint in a virtualized box hosted by our new Dell T320 server in the picture.

That was work.

The absolute low point was spending my birthday (July 24th and do-not-ask-please) with a very sick new Windows Hyper-V server that would not stay running (due to corrupted everything, as it turned out.  Plus a Windows servicing stack that lied to me about what was and what was not installed, another story.)  That afternoon I only remember staggering to my favorite takeout joint in Salem, going home in a daze, nomming down steak tips, and then falling into bed.  The topper was me remoting into that same server four hours later because I could not sleep! (!!)

I am extremely stubborn and hyperfocused with computer problems.  Now imagine 12 months of this.  I’m surprised I’m even still here.

I’m just in time for Windows 8.1, though, and I did get new server hardware at home to write about.  I’m catching up on my gaming, too, and I have no shortage of topics now.

Stay on the channel.

Hac-Man Won the Retrochallenge!

Hac-Man game code

I’ve won the Summer 2012 Retrochallenge!!

Hac-Man is a clone and a recreation of a game I originally wrote on my high school’s minicomputer 30 years ago.  I’m delighted that I was able to get back into retrocomputing, considering I had to throw out almost all of my old computer and electronics history. 

Though I’m very much future-focused (and sometimes depressed for it), I always loved reading old technical books and magazines and  I love it more so when I can run old software and old operating systems like DEC RSTS/E.  I am not done with my retro explorations—I have a whole file share on my home server with hundreds of megabytes of nothing but emulators and system images, most of which I haven’t even had time to yet touch.  (It was this system that hosted the RSTS/E instance from which I developed the game, since I could work on it at my desk and at my laptop during lunch breaks.)

Hac-Man the game is completely finished now;  I’ve thought about making it available to download as a complete system, but it’s hard to do as there are very few terminal emulators that will work for Hac-Man, other than TeraTerm.   Kermit 95 is another possibility for a terminal emulator—it has recently been open-sourced—but from reading about the code, it sounds like quite a fixer-upper that I know I won’t have the time for.

I’d like to recreate my game in QuickBasic.  QB64 seems to be a very ingenious, well-developed reinvention of this classic BASIC interpreter and compiler.   I could create a very nice looking, if retro, Hac-Man, and this is what I’ll probably do if I ever have time.

The final tally:  Hac-Man is contained in two RSTS/E BASIC-PLUS programs, each of them weighing in at 20K and 400 lines each, and I spent roughly 50 hours in July working on the project.

Here’s the final, final video:

Final version of Hac-Man

This’ll be my last retro entry for a little while, as I am forced back to the present by SATV and Microsoft.

Retrochallenge: Closing thoughts and a video

hacman moving 4

I’m a bit too exhausted to write the long post-mortem I had planned for the project.  I got enough of it done to show, but not enough to be a complete game;  the real world won’t let me take any more time on this project.

But it’s been a lot of fun.  RSTS/E is as linked to BASIC as Unix is to C.  Considering the limitations of BASIC, it’s amazing that so many of the system utilities were written in that language.  RSTS will never be a good host for arcade games, but we made it do in 1981. 

I’d like to give a hat tip to my old classmates in the Salem High computer lab:  Randy Moisan, Chris Haight, John Orlowski, Dave Irish, Peter Georgelas, and our department head Thomas Risoldi.  Thanks for the start in this crazy business.

Rough Demo of Hac-Man, a RSTS/E arcade game

Retrochallenge: The last few details of Hac-Man

hacman title

There are just a few details left to explain. When I first thought of recreating my old BASIC game, I’d planned to have some bells and whistles like a high-score screen and an attract mode like in a real arcade game.

Very late in development, I ran out of time and memory to include all this in one executable, and I wasn’t sure if I would have a complete game for the contest. 

Fortunately, fate went in the other direction;  Hac-Man will have a front end with animation, a help screen and high scores.  It will also have the “halftime show” that was in the original game—and in my original clone.

RSTS/E BASIC, like most BASICS, has a mechanism for starting other programs from within a program:  The CHAIN statement.


This code, if I’m not debugging will call HACMAN.BAC and start it at line 9000.  The .BAC extension indicates a compiled program;  CHAIN will fall back to the uncompiled program if the compiled program isn’t found, so it’s recommended practice to always specify .BAC.

(The DEBUG% variable is not part of RSTS/E BASIC, but is my own convention I’ve used for debugging in all my code.)

OK, but how do we pass information from one program to another.  This line of code is run in the Hac-Man game engine when the player loses the game.  The program should then pass the score back to the front end so it can be included in the high score list if possible.

RSTS/E has a feature it calls “core common”.  This is a 128-byte area that the operating system keeps for each job, and it is shared amongst all the processes in each job.   The RSTS/E command processor uses core common to pass parameters to system programs from the command line.

23020 XX$=SYS(CHR$(8%))

We construct a string to pass back to our front end.  The first characters of the string are “HACMAN”, our magic signature that the other program uses to verify that it’s valid.

Next, the function CVTF$(SCORE) adds the score as a binary string.  Some explanation:  In RSTS/E, BASIC can use either 2-word floating point or 4-word floating point values, determined at system generation.  I generated my own RSTS/E system but I don’t remember which option I selected.  (And in the era of emulation, there’s no saying I could not generate a system with 4-word FP.) 

The string fragment SPACES$(12-LEN(CVTF$(0 ))) accounts for this possibility;  it pads the string with spaces for the next two values.

CVT%$(LEV%) and CVT%(PLAY%) convert these integers to binary;  integers are always 2 bytes so this is straightforward.

Here is the corresponding code on the front end:

8500 GM$=SYS(CHR$(7%)) ! Get string from core common
8509 !Validate string
8510 IF LEFT(GM$,6)<>"HACMAN" GOTO 1000 ! If no score passed, resume attract loop
8520 SCORE=CVT$F(MID(GM$,7,LEN(CVTF$(0))))
8530 LEV%=CVT$%(MID(GM$,12,2))

This code is called from the Hac-Man game engine at game over.  Line 8500 retrieves the string from core common.  Line 8510 checks for a “HACMAN” signature that indicates a valid code.  Line 8520 retrieves the score, and 8530 retrieves the ending level.

systat memory

One last aside, this on memory:  I had forgotten how little memory I had on RSTS.  The memory in the BASIC interpreter, and the memory in my TECO screen editor more or less tracked together.  The biggest program I could get in both the editor, and BASIC was about 19,000 bytes, just less than 20K.

That included white space.  It isn’t free here, and that will surprise a lot of modern developers.

Several times, I had to back out of programming changes and refactor my code.  Hac-Man likely represents the most complex programming in RSTS/E.  In 1981, I was complimented on my work by a DEC field service engineer (“Wow, is that Pac-Man!?”) who told us that was the most ingenious program he had ever seen.

It is as good as I can possibly get it.

Next:  Closing words, and a video.

Retrochallenge: Hac-Man Munch Time!

Hacman and Ghosts

After a month at recreating this old game, I have the AI kinda-sorta working.  Here’s how it’s supposed to work.

First, I must explain that the original game had no AI.  All we learned in those days about AI was in two lines of BASIC that were in virtually every book on BASIC, including the seminal work 101 BASIC Computer Games.  There were many such books up through the mid-80s.

10 Z=INT(RND(0)*10000)
20 D=SQR((X2-X1)*2+(Y2-Y1)*2)

Line 10 computes a pseudo-random number (which will be the same number every time it runs unless I include a RANDOMIZE statement).  Line 20 is a very familiar Euclidean distance formula.

That was it.  That was our AI in almost all of the computer games I and my classmates wrote in those days, and indeed in all of the innumerable collections of BASIC games published in print.

I wanted to do better this time around.   My strategy was inspired by a discussion of the AI of a certain popular game.  I couldn’t copy it as is, but I did take to heart its important lesson:  One can assemble simple behaviors and simple code to make our ghosts have reasonable smarts.

All of the ghosts share AI code;  each ghost has target coordinates that it prefers to go to.  It will take a direction to these coordinates first, if it can.  If not, it will continue in the same direction it’s heading, in hopes of finding a cross-corridor.

If the ghost finds itself blocked, it will then try moving to its left, and then to its right.  Here’s a diagram of how it works for Ink, the “fast” ghost that is most like the red ghost in the original game.

AI strategy for Ink

The other ghosts have different strategies:  Blink tries to move in front of the player.  Pink tries to block the player from behind, and, Sal, the fourth ghost, prefers to hide in a corner.

When the player eats a power pill, the ghosts only have one strategy—to get away from the player as fast as possible.

In testing, I found the ghosts to move very fast in relation to the player, so I added a counter to slow the ghosts down.  Currently, the ghosts move one cycle for every five cycles through the game loop. 

Here’s the annotated code:

12198 !Ghost movement routine
12201 !Apply a delay count before moving ghost;  skip moving if delay timer not expired
12210 SV%(I%)=SV%(I%)-1\IF SV%(I%)>0 THEN 13480 ELSE SV%(I%)=VEL%
12220 IF NOT FNGHB%(SPX%(I%),SPY%(I%)) THEN 12300

Line 12200 starts a FOR loop to iterate through the four ghosts.  Line 12210 applies the delay counter.  Line 12220 calls a function, FNGHB%, that detects if the ghost is in its box.

12229 !If in ghost box, move ghost up through door
12230 IF SSTAT%(I%) THEN 13400 !If in box and eatable, do not move!
12240 SDR%(I%)=2\GOTO 13350 !End ghost box exit AI

If the ghost is in its box, it does one of two things:  If it is eatable, the ghost stays exactly where it is and does not try to leave the box.  If it’s normal, it will move up through the exit door (which I’ve made wide to simplify the AI).  SDR% is an array with direction data for all the moving sprites in the game, including ghosts.

12300 IF NOT SSTAT%(I%) THEN 12330 !Skip if not eatable
12301 !Same strategy for eatable mode for all ghosts
12302 !Preferred: Move away from Hac-Man
12310 GP%=REV%(FNDIR%(I%,SPX%(0),SPY%(0)))
12320 GOTO 13200

If the ghost is roaming the maze and it is eatable, its only strategy is to get away.  Line 12310 gets the reverse of the current direction of Hac-Man.

12323 !Per-ghost target calculations
12330 ON (I%-GHOST%)+1 GOSUB 12400,12500,12600,12900
12340 IF DEBUG% THEN XX$=FNSP$(SPDEAD%,PX%,PY%) !Indicate target square in debug
12350 GP%=FNDIR%(I%,PX%,PY%)

Otherwise, the target square for each ghost is calculated.  Line 12340 is some debugging code to display the target square on the playfield.  Line 12350 calculates the direction to the target square.

12398 !Ink: Head directly for Hac-Man
12400 PX%=SPX%(0)\PY%=SPY%(0%)\RETURN
12498 !Blink:  Head in front of Hac-Man
12500 PX%=SPX%(0)+DX%(SDR%(0))*2\PY%=SPY%(0)+DY%(SDR%(0))*2\RETURN
12598 !Pink: Goes behind Hac-Man
12600 PX%=DX%(SDR%(0))+DX%(SDR%(7))\PY%=DY%(SDR%(0))+DY%(SDR%(7))\RETURN
12895 !Sal: Go for Hac-Man if far, hide when close
12920 PX%=70%\PY%=5\RETURN !Sal's corner is in upper right

Each ghost’s target square is calculated here.  This code was much shorter than I thought it would be.  Line 12400 handles Ink’s AI.  Blink is handled at line 12500.  Pink is at line 12600.  Sal is slightly more complicated:  If he’s far away (greater than 8 characters) from Hac-Man, he’ll head towards him, but when he gets closer, he’ll run and hide to the upper right corner.

13195 !Select direction:  Priority is Preferred (calculated), straight-ahead, sprite left, sprite right
13200 DIM G%(3)
13210 G%(0)=GP%\G%(1)=SDR%(I%)\G%(2)=FNRLD%(SDR%(I%),-1)\G%(3)=FNRLD%(SDR%(I%),1)
13220 IX%=0
13230 GD%=FNOBJ%(G%(IX%),SPX%(I%),SPY%(I%)) !Check each direction if clear
13240 IF GD%=4 OR GD%=5 THEN XX$=FNTUN$(I%,GD%)\GOTO 13460
13250 IF GD%<=2 THEN SDR%(I%)=G%(IX%)\GOTO 13350
13260 IF IX%<=2 THEN IX%=IX%+1\GOTO 13230
13350 XX$=FNRD$(SPX%(I%),SPY%(I%))
13440 SPX%(I%)=SPX%(I%)+DX%(SDR%(I%))\SPY%(I%)=SPY%(I%)+DY%(SDR%(I%))
13450 IF NOT SSTAT%(I%) THEN IS%=I% ELSE IS%=9 ! Draw ghost sprite or eatable sprite
13460 XX$=FNSP$(IS%,SPX%(I%),SPY%(I%))
13480 NEXT I% !End AI routine

To make it easier on me, I used another array, G%, to hold the possible directions a ghost would take.  Again, the ghost moves in this order:  1) preferred direction, 2) current direction or straight ahead, 3) left turn, 4) right turn.

Lines 13220 through 13260 form the direction determining loop.  Line 13230 call the background object detection function FNOBJ%.  Line 13240 has special-case code and calls another special function FNTUN$ for the tunnel, which the ghosts will take.  If FNOBJ% returns 0 (empty space), 1 (dot) or 2 (pill), the direction is good and the ghost will take that, in line 13250.

Otherwise, the code tries the next direction from G%.  Line 13270 is debugging code that triggers if the four choices in G% are exhausted.  (There are no blind alleys in the maze.  There should not be.)

Once the ghost has a direction the rest is straightforward.  Line 13350 erases the ghost in its old location.  Line 13440 updates the ghost’s coordinates.  Line 13450 accounts for the ghost’s normal sprite or eatable sprite and line 13460 draws the sprite.  Finally, line 13480 ends the main FOR loop for the ghost AI.

With that, the major work behind Hac-Man is finished.

I only have a few more posts left before the end.  I’ll cover the last technical details in the next post.  My last post will have a video, my closing thoughts, and a dedication to close out the July Retrochallenge.