• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Mac SE ADB Controller

tashtari

PIC Whisperer
"I've discovered more writing on the parchment!"

Looking at the code some more, based on the timing in sending the '1' start bit, I think the external clock is 2 MHz exactly.

Also, further confusing the issue about the data direction registers, there are a pair of subprograms that ostensibly clock a byte into and out of the VIA using the same pin in both directions (pin 9, RB3, CB2 on the VIA). I had previously thought this was an output. This doesn't make sense unless the PIC's GPIO ports are open-collector - a 1 meaning let float and a 0 meaning pull to ground. It'd explain some other stuff I'm seeing in the code. Thing is, that's not how the GPIO ports on the PIC16F54 work. Maybe Apple made some kind of deal with Microchip to make a special open-collector version of the PIC16CR54, because that's not how the PIC16CR54 works, either...

This is a problem, because it means one can't shim a couple instructions in to make the PIC16F54 work like the special Apple PIC16CR54, nor is there a register substitution that can be made to do the same. At this point, what I've seen makes me think it'd be better to target imitating the chip rather than duplicating it.
 

tevruden

Member
I checked both pin 9 from the GLU and pin 16 on the PIC, and my scope reads 3.672 MHz but super jittery. I checked pin 6 and 7 for any sort of signal but didn't see any. I have logic analyzer dumps that track pins 1-3, 8-10, 17 and 18 if that'd shed light on anything.
 

tashtari

PIC Whisperer
my scope reads 3.672 MHz
Huh, that surprises me. The code I was basing that off of had exactly 17 cycles between pulling the ADB pin low and releasing it, which at a 2 MHz clock (500 kHz instruction clock) is 34 us, which is almost 35 us, the nominal low time for a '1' bit in ADB.
 

tashtari

PIC Whisperer
I've been attempting to make some sense of the disassembly. I've got some fairly substantial pieces worked out, but I don't really understand what the protocol is between the VIA and the PIC. CB1 and CB2 are a clock/data synchronous serial port, that's clear, PB5 and PB4 seem to be control signals from the VIA, but their significance is still opaque. PB3's purpose is even less clear; sometimes it seems to be pulled low to signal an error, but it's also pulled low to signal that one of the devices on the bus has done an SRQ. Dunno.

Anyway, I'm uploading what I've got so far in case this is useful to anyone else.
 

Attachments

  • macse_adb_asm_20220311.zip
    6.7 KB · Views: 13

mdeverhart

Well-known member
The MiST project has an implementation of the ADB controller wired up to a model of the VIA. The VIA core is used in a number of other projects, so hopefully it’s close to the actual VIA hardware.

 

demik

Well-known member
Also, further confusing the issue about the data direction registers, there are a pair of subprograms that ostensibly clock a byte into and out of the VIA using the same pin in both directions (pin 9, RB3, CB2 on the VIA). I had previously thought this was an output. This doesn't make sense unless the PIC's GPIO ports are open-collector - a 1 meaning let float and a 0 meaning pull to ground. It'd explain some other stuff I'm seeing in the code. Thing is, that's not how the GPIO ports on the PIC16F54 work. Maybe Apple made some kind of deal with Microchip to make a special open-collector version of the PIC16CR54, because that's not how the PIC16CR54 works, either...
Could it be that since that's port is connected to the VIA, it's using some VIA shenanigans or even the pullup from the VIA if it's present ?
 

tashtari

PIC Whisperer
I realize this is a very long long shot, but does anyone have an SE board with a socket for the PIC, a PIC16F54, something that can program it, and a logic analyzer?

I modified the dumped firmware into a build for the PIC16F54 that is meant to mimic the open-collector output of the original chip, and it works well enough for the machine to boot, but not well enough for the ADB to actually work, and some observations of the bus would go a long way toward figuring out what's going on...
 

Attachments

  • macse-adb.zip
    11.4 KB · Views: 3

Skate323k137

Well-known member
I realize this is a very long long shot, but does anyone have an SE board with a socket for the PIC, a PIC16F54, something that can program it, and a logic analyzer?

I modified the dumped firmware into a build for the PIC16F54 that is meant to mimic the open-collector output of the original chip, and it works well enough for the machine to boot, but not well enough for the ADB to actually work, and some observations of the bus would go a long way toward figuring out what's going on...
I would have to see if any of my SE logic boards have that IC socketed. Exactly which chip is it on the logic board? Is it usually in a socket?

Otherwise I do have PICs, a means to write them, and a logic analyzer
 

tashtari

PIC Whisperer
Exactly which chip is it on the logic board?
Wikipedia has a picture of it here.

Is it usually in a socket?
No, sadly, it's not, you'd have to install one yourself...

I did get someone on Discord to test it, and the code works perfectly, except, due to differences between the original PIC and the PIC16F54, it runs twice as fast as it should. D'oh. I'm currently working on porting it to the PIC16F88, a newer PIC that has the same pinout...
 

tashtari

PIC Whisperer
The code is a mess and the comments are not to be relied upon, but here it is, a working port of the Mac SE ADB controller to the PIC16F88, and thusly a pin-compatible drop-in replacement. I'm going to try and clean it up, finish trying to understand what the original code was doing and comment as such, but here it is in its current state in case anyone wants to have a look and/or try.
 

Attachments

  • macseadb88-withsource.zip
    7 KB · Views: 28

tony359

Active member
Hello @tashtari

That's an impressive job indeed! I might need to replace my ADB chip on my SE so I might give it a go. However, someone suggested I could do with a PIC16F87, would that work anyways?

Thank you!
 

tashtari

PIC Whisperer
Hello @tashtari

That's an impressive job indeed! I might need to replace my ADB chip on my SE so I might give it a go. However, someone suggested I could do with a PIC16F87, would that work anyways?

Thank you!
Yes, a PIC16F87 should work as well as a PIC16F88, the former is just the latter without the ADC (which the ADB controller doesn't use). I would think they'd be binary compatible, but I have not personally tested this.
 

tony359

Active member
Thank you! I guess I can let you know once I test it!

I have a TL866II - any recommendation from anybody about that? I read there might be some issues with that particular programmer?
 

Phipli

Well-known member
Thank you! I guess I can let you know once I test it!

I have a TL866II - any recommendation from anybody about that? I read there might be some issues with that particular programmer?
If you make sure I have the right project file or binary, sort postage and the chip, I can flash one for you if you like? I'm in the UK and have a PIC programmer. Ignore me if you want to sort it yourself :) just offering in case it helps.
 

tony359

Active member
Your offer is appreciated! Let me test myself first - We don't even know if it's going to work apparently! But thanks for offering!
 

Snial

Well-known member
Was talking with @Scott Squires about this yesterday evening and looked into it a bit. I think the biggest reason nobody's seeing any activity when they program a PIC16F54 with this firmware is that it doesn't ever set the TRIS (data direction) register - the I/O pins are always in a high-impedance state. Apple must have struck some kind of custom deal with Microchip that the TRIS register would be pre-programmed, though no version of the chip for which I've been able to find a spec sheet offers this as a feature. Weird. It might be possible to modify the firmware so the TRIS register is set on startup, but this would take some creativity because the firmware appears to use all 512 words of the PIC16F54's memory; I don't see anything in the disassembly that looks like junk.

Other observations:
  • The firmware does not make use of the PIC16F54's built-in timer and only uses the instruction clock for timing. It also does not use the watchdog timer, and hence doesn't make use of the OPTION register at all.
  • According to the bomarc schematic, the bus pin of the SE's two ADB ports is connected both to pin 2 and pin 3. Pin 3 is the clock input to the built-in timer that the firmware doesn't use. Weird.
  • Pin 2 (RA3, the pin sensing the ADB bus line) is always set the opposite of pin 1 (RA2, the pin which, when high [I think] drives the ADB bus low), even though pin 2 is an input and what it's set to shouldn't matter. Weird.
  • On the basis of the unrolled loop that reads the command response from a device (function_029 through function_049), the external clock (pin 16; pin 9 from the GLU) I'm guessing at somewhere around 2.5 MHz. It's hard to say exactly, it looks like the code is meant to accept a lot of variance in the device's timing.
  • Assuming I'm right about the external clock speed, the oscillator selection should be the "XT" oscillator and the configuration word should be 0b000000001001 (code protection off, watchdog timer off, XT oscillator mode).
  • The firmware reads pins 6 and 7 (RB0 and RB1) in function_071 even though these don't appear to be connected to anything on the bomarc schematic. Weird.
  • The firmware uses the uppermost eight bytes of its teensy twenty-five-byte SRAM as a data buffer (ADB frames contain a maximum of eight bytes).
  • Based on usage, I'm reasonably sure that pins 8, 9, and 10 (RB2, RB3, and RB4; CB1, CB2, and PB3 from the VIA according to the bomarc schematic) are outputs from the PIC, and that pins 17 and 18 (RA0 and RA1; PB4 and PB5 from the VIA according to the bomarc schematic) are inputs to the PIC.
I hope someone finds this useful. If anyone has anything else by way of burning questions, let me know - I have a halfway-decent eye for PIC assembly and can at least try to figure it out.
I've just been doing a bit of observation on the PIC firmware. There are several places where PORTA is set to 0xfb.

000: cfb movlw 0xfb
001: 025 movwf PORTA ; reg: 0x005
..
039: cfb movlw 0xfb
03a: 025 movwf PORTA ; reg: 0x005
..
098: cfb movlw 0xfb
099: 025 movwf PORTA ; reg: 0x005
..
0a5: cfb movlw 0xfb
0a6: 025 movwf PORTA ; reg: 0x005
..
0a9: cfb movlw 0xfb
0aa: 025 movwf PORTA ; reg: 0x005
..
0bb: cfb movlw 0xfb
0bc: 025 movwf PORTA ; reg: 0x005
..
16e: cfb movlw 0xfb
16f: 025 movwf PORTA ; reg: 0x005
..
1b1: cfb movlw 0xfb
1b2: 025 movwf PORTA ; reg: 0x005
..
1b4: cfb movlw 0xfb
1b5: 025 movwf PORTA ; reg: 0x005

Not all of them will be time critical, nor be at stack level 2.

We can replace some of these with a subroutine:

PortAReset:
movlw 0xfb
movwf PORTA
retlw 0xfb

And replace the pair of instructions with:
call PortAReset

Providing that at least 3 of these can be substituted this gives us a net saving of at least 1 word; enough for a TRIS instruction, up to 9 might be replaceable, a saving of up to 6 words.

Secondly, function_013 to _015 is a function that fills memory. But also, function_001: clears memory too. If we replace

007: 060 clrf INDF ; reg: 0x000
008: 3e4 incfsz FSR, F ; reg: 0x004
009: a07 goto function_001

in function_001 with:

movlw 0x00
call function_014

We'll certainly save 1 word, because function_001 isn't time critical. Again, enough for a TRIS instruction.
 

tashtari

PIC Whisperer
I've just been doing a bit of observation on the PIC firmware. There are several places where PORTA is set to 0xfb.

000: cfb movlw 0xfb
001: 025 movwf PORTA ; reg: 0x005
..
039: cfb movlw 0xfb
03a: 025 movwf PORTA ; reg: 0x005
..
098: cfb movlw 0xfb
099: 025 movwf PORTA ; reg: 0x005
..
0a5: cfb movlw 0xfb
0a6: 025 movwf PORTA ; reg: 0x005
..
0a9: cfb movlw 0xfb
0aa: 025 movwf PORTA ; reg: 0x005
..
0bb: cfb movlw 0xfb
0bc: 025 movwf PORTA ; reg: 0x005
..
16e: cfb movlw 0xfb
16f: 025 movwf PORTA ; reg: 0x005
..
1b1: cfb movlw 0xfb
1b2: 025 movwf PORTA ; reg: 0x005
..
1b4: cfb movlw 0xfb
1b5: 025 movwf PORTA ; reg: 0x005

Not all of them will be time critical, nor be at stack level 2.

We can replace some of these with a subroutine:

PortAReset:
movlw 0xfb
movwf PORTA
retlw 0xfb

And replace the pair of instructions with:
call PortAReset

Providing that at least 3 of these can be substituted this gives us a net saving of at least 1 word; enough for a TRIS instruction, up to 9 might be replaceable, a saving of up to 6 words.

Secondly, function_013 to _015 is a function that fills memory. But also, function_001: clears memory too. If we replace

007: 060 clrf INDF ; reg: 0x000
008: 3e4 incfsz FSR, F ; reg: 0x004
009: a07 goto function_001

in function_001 with:

movlw 0x00
call function_014

We'll certainly save 1 word, because function_001 isn't time critical. Again, enough for a TRIS instruction.
Sorry, I should be doing a better job of sharing my progress on this. My firmware for the PIC16F87/88 uses timing-neutral writes to the port - with appropriate initialization of the port latches (which can be accomplished easily since the 87/88 has lots of spare program memory), it's possible to replace the movlw/movwf PORTA with movlw/tris PORTA, which has no effect on the timing.
 

max1zzz

Well-known member
Hello @tashtari

That's an impressive job indeed! I might need to replace my ADB chip on my SE so I might give it a go. However, someone suggested I could do with a PIC16F87, would that work anyways?

Thank you!
Can confirm the 87 and 88 both work - I have used a 88 in a SE and a 87 in a IIcx (using a little QFN to PLCC adapter board I made) both of which worked perfectly
 

Snial

Well-known member
Sorry, I should be doing a better job of sharing my progress on this. My firmware for the PIC16F87/88 uses timing-neutral writes to the port - with appropriate initialization of the port latches (which can be accomplished easily since the 87/88 has lots of spare program memory), it's possible to replace the movlw/movwf PORTA with movlw/tris PORTA, which has no effect on the timing.
It's OK, somehow I hadn't picked up on the latest posts and was replying to a post back in March 2022 before the PIC16F87/88 version was released. I haven't checked your version at all, I was just looking at the original PIC 16x54 version and doing a bit of analysis on the code structure. Is the initialisation timing dependent too?
 
Top