|
Joined: Feb 2004
Posts: 2,603 Likes: 307
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,603 Likes: 307 |
Ok I thought I'd try to redump the 8048 on the Buffered Grappler+, and did it around 10 times and kept getting the exact same results.
Therefore, something must be wrong. Since it's powered by a USB cable, I dug around and found a different usb power supply and guess what - the read is slightly different. If you got a different dump with one thing, maybe you should use a better power supply and re-dump everything you dumped with that setup and see if any other things have bad bits.
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
Original Grappler schematic: https://archive.org/details/manualsonline-id-6b56a0aa-4089-4658-a2c6-de559ed3a773/page/n17/mode/2upThe ProGrappler manual doesn't have schematics unfortunately. https://archive.org/details/ProGrappler/mode/2upI was doing a little bit of circuit tracing on the ProGrappler and two of the data lines are swapped I think. I'll have to check because I can't remember exactly. According to my notes: "I was looking at the prograppler dump and it looked really horrible, so I thought I'd do some checking on the board with a multimeter, looks like they did a little bit of "protection" where they swapped d3/d4 and a2/a3 and a6/a7."
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
Hi Vas,
The dumper in question is a Willem LPT 6.0 which I got specifically to dump the 8048. Pretty much everything else I've been doing has been with a TL866 II Plus. With the Willem the 8048 needs some different voltages and uses a special adapter. So it's really just this one dump and it exposed the bad power supply issue.
|
|
|
|
Joined: Feb 2004
Posts: 2,603 Likes: 307
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,603 Likes: 307 |
Interesting, this one doesn’t automatically generate strobe pulses, doesn’t use Apple’s trick of flipping a ROM address line while waiting for the printer to acknowledge a character, doesn’t generate interrupts, and doesn’t have DIP switches. Looks like a very simple card. The ProGrappler manual doesn't have schematics unfortunately. https://archive.org/details/ProGrappler/mode/2upI was doing a little bit of circuit tracing on the ProGrappler and two of the data lines are swapped I think. I'll have to check because I can't remember exactly. According to my notes: "I was looking at the prograppler dump and it looked really horrible, so I thought I'd do some checking on the board with a multimeter, looks like they did a little bit of "protection" where they swapped d3/d4 and a2/a3 and a6/a7." Yeah, looks like by this time they were trying to make it harder for people to clone the card. This one probably requires more reverse-engineering to emulate.
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
I think the Grappler and the "Orange Interface" are actually the same card but with different roms. The Grappler adds graphic dump capability (but only single printer specific, like Epson). The schematic in the Grappler manual says "Orange Interface".
I can try to trace out the connections on the Pro Grappler but I'm *really* slow at it with my multimeter.
|
|
|
|
Joined: Feb 2004
Posts: 2,603 Likes: 307
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,603 Likes: 307 |
I added the Grappler (without the +). It occasionally drops a character. With logging turned on, you can see that it really doesn’t wait for the previous character to be acknowledged before outputting another character in these cases. It isn’t a “time travel” effect where it doesn’t have time to see the acknowledge latch being cleared. I don’t have the energy to debug it further, but it could be another bad dump, or an original bug.
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
Hmmmm. It all looks very reasonable, ./unidasm -arch m6502 -basepc 0xc800 grappler_2716_U6_eps_1c1982.bin | grep c08 -A 6 -B 5
cbcb: b9 81 c0 lda $c081, y
cbce: 29 04 and #$04
cbd0: ea nop // guess they don't care about paper out
cbd1: ea nop
cbd2: b9 81 c0 lda $c081, y
cbd5: 29 02 and #$02 // printer not selected
cbd7: f0 46 beq $cc1f
cbd9: b9 81 c0 lda $c081, y
cbdc: 29 08 and #$08 // loop here if busy
cbde: d0 f9 bne $cbd9
cbe0: bd 38 07 lda $0738, x
cbe3: 29 08 and #$08
cbe5: f0 04 beq $cbeb
Just running one CTRL+I G will start printing garbage. Does the ap2000 have to synchronize itself just as the grappler is synchronizing? It seems that the grappler is doing all the synchronizing, and the ap2000 and its e05a30 device doesn't have to synchronize.
machine().scheduler().synchronize(timer_expired_delegate(FUNC(a2bus_grappler_device::set_strobe), this), 0);
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
Just as an experiment to see if it's synchronization issues I put config.set_maximum_quantum(attotime::from_usec(15)); into device_add_mconfig and it seemed to help. One other thing I noted was that reads to C0nx have side effects, so maybe a debugger guard would be good here (for completeness): Interesting that they didn't worry about the R/W line for access to C082 and C084 so reads can set/clear the strobe line as well as writes.
u8 a2bus_grappler_device::read_c0nx(u8 offset)
{
LOG("Read C0n%01X\n", offset);
if (BIT(offset, 1)) // A1 - assert strobe
machine().scheduler().synchronize(timer_expired_delegate(FUNC(a2bus_grappler_device::set_strobe), this), 0);
else if (BIT(offset, 2)) // A2 - release strobe
machine().scheduler().synchronize(timer_expired_delegate(FUNC(a2bus_grappler_device::set_strobe), this), 1);
|
|
|
|
Joined: Feb 2004
Posts: 2,603 Likes: 307
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,603 Likes: 307 |
Here’s a log of it missing a character:
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Write C0n1=20
[:sl1:grappler] Output data 20
[:sl1:grappler] Read C0n2
[:sl1:grappler] Write C0n2=20
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] Clearing acknowledge latch
[:sl1:grappler] BUSY=1
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] BUSY=0
[:sl1:grappler] Read C0n4
[:sl1:grappler] Write C0n4=20
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Write C0n1=20
[:sl1:grappler] Output data 20
[:sl1:grappler] Read C0n2
[:sl1:grappler] Write C0n2=20
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] Previous data not acknowledged
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] Read C0n4
[:sl1:grappler] Write C0n4=20
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] /ACK=0
[:sl1:grappler] Set acknowledge latch
[:sl1:grappler] BUSY=1
[:sl1:grappler] BUSY=0
[:sl1:grappler] /ACK=1
It writes C0n2 to assert /STROBE, and the acknowledge latch is cleared in a callback from the scheduler. There are no intervening reads of C0n1 where it could mistakenly still see the acknowledge latch still set from the previous byte (this could happen if the timeslice wasn’t aborted fast enough). It doesn’t wait for the acknowledge latch to be set before sending the next byte. The acknowledge after the second byte comes very quickly because it’s actually the acknowledge for the first byte, and the second byte is lost. Now look at a more normal pair of bytes:
[:sl1:grappler] Write C0n1=20
[:sl1:grappler] Output data 20
[:sl1:grappler] Read C0n2
[:sl1:grappler] Write C0n2=20
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] Clearing acknowledge latch
[:sl1:grappler] BUSY=1
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] Read C0n4
[:sl1:grappler] Write C0n4=20
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] /ACK=0
[:sl1:grappler] Set acknowledge latch
[:sl1:grappler] BUSY=0
[:sl1:grappler] /ACK=1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Write C0n1=20
[:sl1:grappler] Output data 20
[:sl1:grappler] Read C0n2
[:sl1:grappler] Write C0n2=20
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] Clearing acknowledge latch
[:sl1:grappler] BUSY=1
[:sl1:grappler] Output /STROBE=0
[:sl1:grappler] Read C0n4
[:sl1:grappler] Write C0n4=20
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] Output /STROBE=1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] Read C0n1
[:sl1:grappler] /ACK=0
[:sl1:grappler] Set acknowledge latch
[:sl1:grappler] BUSY=0
[:sl1:grappler] /ACK=1
See how it sits in a polling loop waiting for the acknowledge latch to be set before it continues with the next byte?
|
|
|
|
Joined: Feb 2004
Posts: 2,603 Likes: 307
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,603 Likes: 307 |
OK, I probably just suck at 6502, but what is the purpose of tay immediately followed by tya? C940 lda #$87 A9 87
C942 jsr $cbc0 20 C0 CB
C945 tay A8
C946 tya 98
C947 cmp #$8d C9 8D
C949 bne $c968 D0 1D
C94B lda #$00 A9 00
C94D sta $0438, x 9D 38 04
|
|
|
2 members (2 invisible),
197
guests, and
0
robots. |
Key:
Admin,
Global Mod,
Mod
|
|
Forums9
Topics9,328
Posts122,128
Members5,074
|
Most Online1,283 Dec 21st, 2022
|
|
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!
|
|
|
|