News:

Want an XLerator? Please participate in the market research thread: https://lisalist2.com/index.php/topic,594.msg4180.html

Main Menu

A Lisa Inside An FPGA

Started by AlexTheCat123, September 04, 2025, 05:20:35 PM

Previous topic - Next topic

warmech

Hahaha, you're not kidding; there are a few Lisa Rambos out there.

Thinking he's talking about the LRambo mod as seen here.

Manzanavila

Hi, as the colleague says, the LRambo card was a mod for a Sun Remarketing 2mb RAM card that supported the 4mb option for use only with the Mac system, not with Lisa OS.

Manzanavila

This is a render of a 2MB SUN REMARKETING card. If you look in the center, there's a jumper to convert it to a 4MB card. A mod to the Lisa motherboard is necessary for it to work.

AlexTheCat123

Good suggestion, but I probably won't add 4MB of RAM because of the extra cost of a second RAM chip. The boards are already rather pricey, and another chip just increases that price further. And plus, I think only a select few people would use 4MB to begin with. I'm guessing that most people who want an FPGA Lisa are probably going to be using it to run the unique LOS/Workshop/Xenix/UniPlus OSes as opposed to your generic Mac OS that can be run (and run better, no less) on any old Mac.

AlexTheCat123

Sorry for the slower pace of updates lately! School has really picked up as we near the end of the semester, and I've had a lot less time to work on things than I did before. There's not a whole lot left to do at this point though; the main problems that come to mind are hard disk issues, and they might be ESProFile's fault.

I fixed one hard disk issue, where UniPlus would assert CRES midway through the boot process, which would obviously completely break communications with the ProFile. I had temporarily gotten around this by telling ESProFile to just ignore CRES, but I went in and fixed it for real a few days ago. It turns out that I was operating under the faulty assumption that the CRES pin from the VIA would always be set to an output, so I was ignoring the state of DDRB and just blindly piping the pin out to the CRES logic. But this doesn't work if the VIA sets CRES to an input and then puts a 0 in its output register; this will pull my CRES low even though it should actually be floating (which defaults to the desired state of high). So all I had to do was check the proper bit in DDRB. If the VIA's CRES pin is set to an output, then pass CRES on through, but if it's set to an input, then just force our CRES VIA output high.

This is really interesting because it means that UniPlus is setting the CRES output to an input for some reason. I wonder why?

The other two somewhat-major issues left to solve are also both ProFile-related.

One is that Xenix fails to boot with a bunch of ProFile handshake errors. On very, very rare occasions, it makes it to the login screen, but it's quite uncommon, and you're completely out of luck if you try it at anything higher than a 20MHz DOTCK. I'm thinking that this is an ESProFile issue more than it is a LisaFPGA issue though. Xenix works fine on the regular ESProFile, so perhaps it's some sort of subtle timing thing with porting it from a standard ESP32 to a slightly-faster ESP32-S3?

The second is that your very first attempt to boot from the onboard ESProFile at the 75MHz DOTCK will always result in an error 84, but then all subsequent attempts (until you hit ESProFile's reset button) will work fine. It's just that first attempt that's the problem, and only at the 75MHz DOTCK; all three lower speeds work fine. Looking at it with the logic analyzer, it seems that the problem is that ESProFile is sending its data bytes to the Lisa with a 1-byte delay, so it sends the Lisa status byte 3 when it expects data byte 0, data byte 0 when it expects data byte 1, and so on. I have no idea why this only happens on the first attempt and then never again, but it's clearly some kind of ESProFile issue!


sigma7

QuoteXenix fails to boot with a bunch of ProFile handshake errors

Reminder that Xenix's ProFile support is known to be problematic and needs patching to work with faster parallel port drives, see:

http://sigmasevensystems.com/xpf_xenix.html

I don't doubt you've just encountered additional bugs .
Warning: Memory errors found. ECC non-functional. Verify comments if accuracy is important to you.

sigma7

QuoteI've never heard of a LisaRambo card and Google and DuckDuckGo both just turn up a reality show contestant. What's a LisaRambo card?

Paul Capes devised a modification for the 512K Apple Lisa Memory Board using larger DRAM chips, making it a 2MB board. When I uploaded his design to CompuServe ca. 1986 (the days of 8.3 filenames), the filename was LRamBo.

The relevant part of the upload is shown here:

https://lisalist2.com/index.php/topic,392.msg2916.html#msg2916

The 4MB Modification referenced in the other replies came later. The initial implementation was using two LRamBo boards (hence the overlap in terminology), with a modification to support the AST RamStak boards coming shortly after.

The Sun Remarketing 2MB SIMM memory board was designed after that, and included the undocumented jumper to support the 4MB Modification.

The 4MB Modification does require modifications to the CPU Board, but not the motherboard. The LRamBo modification to make a 512K board into a 2M board doesn't require modifying any other boards.
Warning: Memory errors found. ECC non-functional. Verify comments if accuracy is important to you.

stepleton

Quote from: sigma7 on April 10, 2026, 07:31:57 PMWhen I uploaded his design to CompuServe ca. 1986 (the days of 8.3 filenames), the filename was LRamBo.

I love details like this. "Compuserve" is also an important clue, as at least at a certain point it only allowed 6.3 filenames (see PDF page 30 here) owing to running TOPS-10 behind the scenes (see also PDF page 243 here). This would explain why it's LRamBo (six letters) and not LisaRamB or LRamBrd or something longer.

The only inconsistency is that the SIXBIT character encoding used for TOPS-10 filenames didn't have lower case characters, so I would have expected the file to be called LRAMBO instead?

sigma7

QuoteI would have expected the file to be called LRAMBO instead?

That seems reasonable/likely.

IIRC, the upload contained three documents (Two pages of reverse engineered schematics of the 512K Memory Board, and one page for the modifications), so it was probably a .sit stuffit archive.

The documents were created on and uploaded from a Lisa running MacWorks XL, so the original files had long (guessing System 3.0, so up to 31 characters) mixed case names. I don't recall if the CompuServe upload process required pre-naming the upload or providing a (possibly different) name upon upload, but I don't see any uppercase "LRAMBO" file/folder/archive names here.

A brief look suggests the filenames in the archive were "MD2 Lisa RamBo Part 1", 2, 3, implying MacDraw 2 documents. The misaligned text in the pdf is a consequence of hastily converting the files to MacDraw II and then (I don't recall what steps) to create a pdf. Sometimes WYSInWYG.

IIRC, MacDraw 2 knew that it was running on a Lisa, and (assumed) that meant rectangular pixels, so would adjust the aspect ratio when drawing to the screen to compensate. However, it corrected in the wrong direction, so if one drew a circle for example, the circle would be about twice as tall as wide on the screen (but would print as a circle).
Warning: Memory errors found. ECC non-functional. Verify comments if accuracy is important to you.

AlexTheCat123

I finally got the idea to try a real ProFile (not sure why I didn't think of that before), and Xenix fails in the same way on there too, so it's looking like a LisaFPGA issue at this point. I wonder what's going on? Maybe another case of a ProFile control pin getting set to an input on the VIA and me making a bad assumption about it, just like on CRES? We'll have to find out!

AlexTheCat123

The semester is finally starting to wrap up, so I'm finally able to get back to work on LisaFPGA again!

Luckily, I've already been able to fix the two bugs that I talked about in the last update, which were:

Quote from: AlexTheCat123 on April 10, 2026, 05:46:20 PMOne is that Xenix fails to boot with a bunch of ProFile handshake errors. On very, very rare occasions, it makes it to the login screen, but it's quite uncommon, and you're completely out of luck if you try it at anything higher than a 20MHz DOTCK. I'm thinking that this is an ESProFile issue more than it is a LisaFPGA issue though. Xenix works fine on the regular ESProFile, so perhaps it's some sort of subtle timing thing with porting it from a standard ESP32 to a slightly-faster ESP32-S3?

The second is that your very first attempt to boot from the onboard ESProFile at the 75MHz DOTCK will always result in an error 84, but then all subsequent attempts (until you hit ESProFile's reset button) will work fine. It's just that first attempt that's the problem, and only at the 75MHz DOTCK; all three lower speeds work fine. Looking at it with the logic analyzer, it seems that the problem is that ESProFile is sending its data bytes to the Lisa with a 1-byte delay, so it sends the Lisa status byte 3 when it expects data byte 0, data byte 0 when it expects data byte 1, and so on. I have no idea why this only happens on the first attempt and then never again, but it's clearly some kind of ESProFile issue!

The Xenix bug ended up being a problem with the 6522 VIA core that I was using. I didn't write the VIA myself, I stole it from the NanoMac project, and up until now I thought it was 100% accurate to the original. But I've discovered several bugs over the past few days, one of which was causing Xenix to fail.

The specific issue that Xenix was having was that it would sometimes ignore the state of the BSY line coming from ESProFile. ESProFile would have BSY low telling the Lisa to wait while it was busy reading/writing to the SD card, but Xenix would sometimes just pretend like it didn't notice and would proceed with sending strobe pulses and expecting the drive to be sending/receiving data in return. And the strange part is that it would only do this sometimes, like once every several hundred ProFile accesses.

After isolating (with some help from Claude) and disassembling the Xenix ProFile driver, I discovered that it operates in an interesting way. During the portions of the code where it's waiting for the drive to raise BSY, there are actually two things that will cause it to move forward with the ProFile transaction. The first is (obviously) the actual raising of BSY, but the other is a timeout on VIA timer 2, which was presumably meant as a watchdog so that the whole computer wouldn't lock up if the ProFile never responded. The odd thing though is that it seems like they never implemented the watchdog; there's seemingly no code that calls the ProFile driver (or within the driver) that actually sets and starts the timer. But I noticed that, despite this, it was still running, timing out, and causing us to proceed before BSY was raised. But why?

Well, it turns out that it was a bug in the VIA like I mentioned earlier! When timer 2 is in one-shot mode (which is the mode that it's in while Xenix is running), you're supposed to load it with a value once, and then it counts down to zero and generates an interrupt when it gets there. After hitting zero, it actually underflows back around to FFFF and keeps counting down again forever, but it only generates the interrupt the very first time it hits zero (hence one-shot mode). But there was a bug in my VIA where, when the timer is in one-shot mode, it actually generates interrupts EVERY TIME it hits zero, not just the first time, which means that an interrupt is generated periodically the entire time that the Lisa is on (although it's masked, so it's just a bit being set in the VIA's IFR, not a physical interrupt going to the 68K).

But since Xenix is constantly polling this bit in the IFR to use alongside BSY as an indicator that it should proceed with the ProFile transaction, these spurious interrupts can cause us to move ahead when we shouldn't if they're timed just right. Which explains why this would only happen sometimes; most of the time, timer 2 would hit 0 at an inconsequential time, but occasionally it would happen while we were waiting for the drive to raise BSY.

Adding one line of code to the VIA fixed the problem so that the timer only generates one interrupt, and now Xenix boots and runs great, including at the full 75MHz DOTCK!

I'm honestly shocked that this hadn't caused a problem in any other OS! I guess none of them use timer 2 in a way in which it's allowed to count without reloading after a timeout, or don't use it in one-shot mode.

Now onto the second issue: the ESProFile thing where it always sends data bytes with a 1-byte skew on the very first transaction after it comes out of reset, but then never again. This turned out to be a caching issue on the ESP32 side of things, nothing wrong with LisaFPGA itself. Basically, the code that handles the really time-sensitive reading of strobe pulses from the Lisa and the sending of data in response isn't loaded into the ESP's instruction cache until it's been executed for the first time, and it takes quite a while to get it loaded in there when it first gets called. In fact, it takes so long that the ESP misses a strobe pulse before the code is loaded in and executed when the Lisa is running at a 75MHz DOTCK, which is what causes all of the data bytes to be sent with a 1-byte skew. But then all subsequent accesses are fine because the code is already cached at that point.

The fix here is simple: add the IRAM_ATTR attribute to all of these time-sensitive sections of code to tell the linker to place them in fast instruction RAM (as opposed to slow flash) from the very start, so that they never have to be loaded from the flash to begin with. Now things work flawlessly!

And one other thing: I got GEM working! It has never worked up until this point, and I thought that there was actually something wrong with my FPGA implementation, but no. It turns out that GEM just doesn't like having 2MB of RAM to play with. Dropping down to 1MB causes it to work great, and it's insanely fast when you're overclocked to 75MHz!

Unfortunately, it's not all good news. There are still several (rather small) problems left that need to be solved, and I just discovered one more that's actually a regression from where we were before.

This newly-discovered problem has to do with BLU, and it's pretty strange. BLU boots from a floppy just fine, but fails to boot from a hard disk or properly read a hard disk from the Hard Disk submenu. It gets data back from the disk, but the data is all shifted out of place (for example, the drive name is "PPROFFILE" or something like that). Upon closer inspection, it seems as if, for every 4 strobe pulses that BLU tries to send to the drive, the VIA actually only outputs 3 of them, one really long one and 2 normal-length ones.

I've always thought that BLU has a really unique strobe pattern compared to other OS's, so maybe that had something to do with what was going on. I decided to disassemble that section of the code to find out, and BLU sure does do things in a unique (and really clever) way!

If you've ever looked at BLU's strobe pulses, you'll notice that it always sends them in really fast groups of 4, with longer gaps between the groups. And the groups themselves seem impossibly fast; even if you sent two instructions immediately after each other, they wouldn't be able to touch the VIA that fast.

Well, that's the trick that BLU is using: it's not actually multiple instructions! Most ProFile drivers just use a series of MOVE.B's to grab each ProFile byte from the VIAs sequentially, but BLU uses a single MOVEP.L to grab 4 bytes at once instead! MOVEP grabs alternate bytes from within a word, and stitches them together into the destination register, and it's intended to allow the 68K to interface with 8-bit peripherals like the VIA that you'd like to read from sequentially but are only hooked up to one half of the 16-bit bus. The .L part is important because it's making the 68K do a longword operation in which it reads 4 bytes (32 bits) from the VIA, returning the next 4 bytes of ProFile data. Each read from the VIA's input register automatically pulses the strobe, so the very execution of each of MOVEP's reads will fetch the next byte without any extraneous instructions having to do anything.

But this might sound like a problem; we're reading from 4 sequential addresses (really 8 addresses since it's a MOVEP that jumps 2 bytes ahead on each read) but want all of our reads to be targeted to one single input register in the VIA. Well this actually works out just fine thanks to the way that the I/O board is designed. The VIA is addressed by address lines 6 down to 3, meaning that each register happens to be mirrored exactly 8 times. So even though we're reading 8 different addresses, they all point to the input register!

That's really clever, but why are our strobe pulses getting messed up? Well, that's the part that I haven't fully figured out yet, but it seems like we're somehow flying through each of the individual reads within the MOVEP too quickly. The VIA needs two clock cycles on the E clock in order to pulse its strobe, one to lower it and another to raise it, but for whatever reason the CPU is going so fast that it's already requesting the next data on that second clock pulse instead of leaving the VIA alone to let it raise the strobe, meaning that the strobe never gets raised for that particular address. I have no clue why the CPU isn't respecting this timing that is clearly respected on a real Lisa (and in some of my older builds), but it probably has something to do with VPA and/or VMA being generated at the wrong times (which could lead back to IOCY or CPUC1 on the CPU board), or perhaps me generating the E clock strobes at the wrong times.

My next step is going to be to pull one of my old working designs from a couple months ago off GitHub (apparently this has been broken for several months and I just haven't noticed) and build both the working and broken designs side by side to compare their logic analyzer traces. Hopefully something obvious shows up!

stepleton

Thanks for another fascinating and detailed dispatch, and good luck chasing down these last few bugs!

AlexTheCat123

I figured it out! It was indeed a problem with VMA/VPA not being asserted at the right time relative to the INTIO signal, and it ended up being because the CPU board clock counter that generates the CPU board's 8 timing states wasn't synced properly with the CPU.

I have a 2-step reset system where the T-state counter is pulled out of reset before the CPU is since that counter has to be running before the CPU is, but the T counter has to come out of reset exactly 5 cycles before the CPU to ensure that the T states are properly synced with the 68K's internal timing states. And I used to do it that way, but at one point a couple months ago I increased the reset period for the CPU from a few milliseconds to a full second-ish like the original Lisa to fix some COP issues, but failed to increase the counter reset accordingly to be exactly 5 cycles ahead. So making that adjustment was enough to fix it!

Now I'm going to mess around with MacWorks Plus a bit, and see if I can figure out why it just immediately shuts down whenever you run it at a DOTCK speed higher than the Lisa's stock 20MHz. I guess it's not the end of the world if I can't figure it out since it does work at stock speeds, but it would be nice to have a solution. Basically, right after you get the boot beep and the blinking question mark, the screen will immediately fade to black and the COP turns the Lisa off, so I'm guessing it's some kind of COP communications issue at higher speeds.

AlexTheCat123

I figured out the MacWorks Plus issue, and now it can run at the full 75MHz DOTCK! Although it does require a small patch to your MacWorks Plus disk. It turns out that it was indeed a COP issue like I had guessed. MWP sends the COP a 0x02 (read clock) command once every second or so, meaning that even when the Lisa isn't "doing anything" and you aren't moving the keyboard/mouse, it's still going to be talking to the COP. The COP is supposed to respond to the 0x02 command first with an 0x80, followed by an 0xEy where y is the 4-bit year code (this is why the Lisa can only store years from 1980-1995), and then followed by several more bytes for the day, hour, minute, second, and tenth of a second.

But the MWP COP-reading code is really weird; it waits for the 0x80, and then expects all of the subsequent bytes to come quite quickly, enforcing a pretty strict timeout. And for whatever reason, if the next byte is an 0x00, MacWorks not only aborts the COP read operation, but also jumps to its "dim the screen and power-off" routine. I have no clue whatsoever why a 0x00 response from the COP would be grounds for doing something as drastic as turning off the whole computer, but that's what they chose to do. This explains why the Lisa always turns off at the higher clock speeds; it's just always reading a 0 from the COP on those subsequent bytes after the 0x80. But why?

Well, it's because of that timeout period I mentioned earlier. When the Lisa is overclocked, the 68K is running at 4x-ish its standard speed, but the COP is still at normal speed, so the COP effectively has 4x less time to get the data out to the 68K. This is just too fast for the poor COP to handle (it doesn't assert it's DATA_QUEUED signal in time), so the 68K always times out and MacWorks just gets a 0x00, which is the default value that the register that's supposed to contain the COP response is cleared out with. This situation is supposed to be protected against with a timeout flag that MacWorks sets in the 68K's condition code register, so that the caller of the COP routine can differentiate between reading an actual 0 from the COP (which is grounds for a power-off) as opposed to a timeout that just returns 0 incidentally (which isn't grounds for a power-off). But whoever wrote the flag-setting code clearly wasn't thinking straight. They set the flag in the CCR in the event of a timeout, but then on LITERALLY THE NEXT INSTRUCTION they pop the old contents of the CCR off the stack and overwrite the CCR with it before returning to the caller. So if the flag was set, it just gets clobbered every time. No idea how they missed that!

There are two possible fixes here. One is to prevent the CCR from getting overwritten, but I didn't go that route because there's still no guarantee that the rest of MacWorks would handle the flag correctly given that it never showed up in normal operation. The second was to simply increase the timeout period, which was set to 0x108 and then was decremented to 0 in a DBRA loop. I just upped it to some huge number (luckily, the loading of the counter was a MOVE.L, not a MOVE.W, so there was space in the binary to make it really big) and then it worked at the fully 75MHz DOTCK speed!

I also discovered a problem where the Lisa would refuse to work with a real 800K floppy drive, giving an error 57 whenever the drive was plugged in. It turns out that this problem was just me being stupid; I thought I was running the dual 400K/800K I/O board ROM but I was actually just running the plain old 400K version. Switching to the dual version fixed it right up!

After this, I went through and did a big test sweep through all of the Lisa OS's at all of the different clock speeds, and discovered another BLU problem: it fails its self-check when running with a 60MHz or 75MHz DOTCK. It passes the self-check fine when booting from floppy at these speeds, but not from the ProFile; I think I've just hit the limits of what ESProFile (and real ProFiles, for that matter) can keep up with, and we'll just have to accept that. If you really care about the full 75MHz speed when running BLU, just boot from floppy (or boot from the hard disk at 40MHz or less and then switch up to 75 after it's booted) and you'll be fine.

Another thing: I've been having this really weird issue with LOS 2 where it refuses to display Preferences with a "The Lisa is having technical difficulties..." error, and I've been working on it on-and-off for quite a while, not really making any progress at all. Then today I had the brilliant idea to try the disk image on a real Lisa, and guess what? It had the same problem! It turns out that this whole time, it was just a corrupt disk image, and somehow I hadn't considered that as a potential cause until today. Whoops...

Things are seriously quite close to done at this point. I've had a problem where each time I think I'm about done, I think of several more things that I need to mess around with, but this time I think the RTL/FPGA side of things truly might be finished.

The things that are still left to do at this point, in order from most to least annoying, are:
- Make all of the necessary PCB changes for the Rev. 3 board. There are quite a few of these, and most of them aren't too bad, but some of them like redoing all of the SCC stuff that I completely screwed up aren't going to be fun.
- Write a readme for the GitHub repo that explains everything you need to know about building one of these things.
- Make some kind of automated build/flashing script for as many of the board's components as possible. Right now, you have to manually flash the FT232, FPGA, CP2102 (sort of), and ESP32 one by one, and the FPGA requires programming the chip inside the Vivado GUI. I haven't been using the command line based build system since it makes it annoying to have to switch between the GUI and CLI to view reports and logic analyzer traces, but I think we're at a point now where we can do that; having a script that you can run and have it program all three chips with pre-built firmware files for you would be awesome. And then a second script that builds the actual Vivado project for people who actually want to mess with the code, but you definitely don't want to run that one each time you want to program the chip because it takes over an hour!
- Test the board with Twiggy drives. I might have a pair of Twiggies in my possession in a few weeks for an unrelated reason, so this might not be as unachievable of a task as I previously thought it was. They aren't permanently mine or anything, but I'll very likely have them for long enough to fix any LisaFPGA Twiggy issues that crop up.
- Test a real 400K floppy drive. As I mentioned earlier, I've tested an 800K and it works fine after my ROM fix, but I can't test a 400K at the moment because my 400K drive cable is currently inside a pinball machine in another building at the university that I don't have access to right now. Hopefully I can get it back soon!

One other thing to try and mess with is the onboard ESP32-based floppy emulator. I wrote all of the code for it back in November I think, but I haven't tested the code a single time because I wanted to get the rest of the board running and released publicly before worrying about that.

Assuming the PCBs are here in time for VCF Southwest at the end of the month, I was thinking about getting a loan from my parents and potentially ordering a decent-sized run to sell to people who come to the show. I know there there are some people there who would really love to get their hands on one, but I'm a bit nervous about doing this because if the market isn't as big as whatever I predict, then I'm stuck with a bunch of boards. To judge interest on this, is anybody going to be at VCF Southwest who might want one?

stepleton

I certainly want one but will be nowhere near VCF SW. Consider explaining the situation and asking on 68kmla/TinkerDifferent/VCFed? A link to this thread would help folks who want to know more or who want to confirm that the project is real.