|
Joined: Jun 2001
Posts: 520 Likes: 33
Senior Member
|
Senior Member
Joined: Jun 2001
Posts: 520 Likes: 33 |
Yeah, there's no hope of anything sane if your arm is not 64bits. attotime will kill you for a start.
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
I thought I'd revisit the Silentype and see if I could make sense of why it has two shift clocks. It has just three signal lines going to the printer, SD serial data, SH shift clock and XC store clock. It's a pretty simple protocol, I'm surprised that nobody hooked it up to other computers of the day though it did need a +12V power supply. Anyway, the firmware writes a sequence of 16 bytes of 0x0e or 0x0f to c091 to send the data bits, then 1c, 18, 1c, 0c. 0x0e is a 0 bit and 0x0f is a 1 bit. So why does this work? I couldn't figure out the details until I made a logisim model of the circuit. d1 is the "transitory" shift clock. If you write a 1 to d1, the shift clock goes high when clocked by phi1 then drops. The 673 loads and shifts a bit when the shift clock goes low, so this will clock in the d0 data bit. This is quite clever as we only need to do a single write to shift out a data bit. d4 is the latched shift clock. Writing a 1 to this will make the shift clock go high and stay high. Writing a 0 will clear the shift clock. The d2 store clock is interesting because it gets inverted. So as long as d2 is 1 no load happens, when d2 is 0 then the parallel register gets loaded from the shift register. Whenever d2 goes low and the shift clock is low (both d1 and d4 are zero) the shift register gets reset. This explains why the pattern of 1c 18 1c 0c because it's 1c d4=1 d2=1, 18 d4=1 d2=0 (clocks the parallel load because xc up), 1c d4=1 d2=1 (xc down) 0c d4=0 d2=1 (drops the shift clock which actually causes a bit to shift into the register as a side effect, but we will always load 16 bits so that spurious bit gets shifted to oblivion) Any time you have d4=0 and no shift clock, it resets the shift register, so writing a zero to c091 is an easy way to reset the printer. More cleverness is there, as the d8 of the parallel register output is hooked up to the r/w line of the shift register, and the sd is actually a bidirectional line. Reading from c09x where a01 is true, like c092 will present the shift clock in d6 and the serial data from the shift register in d7. So if you write out a 1 into bit 8 of the parallel register, you can read the contents of the shift register. I suspect that this was used to test out communications with the unit in production perhaps. There's also a 555 to keep the printhead from burning up should you forget to clear the printhead. There's a funny story from Andy Hertzfeld on the development of the Silentype at https://www.folklore.org/StoryView.py?project=Macintosh&story=What_Hath_Woz_WroughtVic was worried about the possibility of the software crashing while it was printing. It was possible for a thermal element to be inadvertently left on indefinitely, which could potentially ruin the thermal elements or even cause a fire. Vic solved the problem by adding a bit of hardware to cut current to elements that were left on for more than 10 milliseconds. He asked me to write a test to verify that his precaution was working as intended.
I wrote code to intentionally leave each thermal element on, to verify that Vic’s safety measure was effective. I was pleased to see that it worked perfectly, but also a little disappointed to miss more exciting behavior if it hadn’t. I thought of something else to try: what if I left an element on for 9.9 milliseconds, before turning it off for only 30 microseconds, then turning it back on again. It would effectively be on for more than 99% of the time while sidestepping Vic’s remedy. I couldn’t resist coding it up to see what would happen, so I fired up the modified test and nervously awaited the results.
At first nothing seemed to happen, except for a low volume humming sound emanating from the printer. Suddenly, after about five seconds, the paper started turning a deep, inky black, spreading out from the print-head organically, almost like a liquid, darker than I had ever seen before. I started smelling an acrid odor and noticed there were open flames near the print-head beginning to spread. I quickly reset the Apple II as I smothered the fire with my jacket. The foul smell drew a small crowd but mercifully no fire alarm.
Last edited by Golden Child; 08/02/21 03:24 PM.
|
|
|
|
Joined: Jun 2001
Posts: 520 Likes: 33
Senior Member
|
Senior Member
Joined: Jun 2001
Posts: 520 Likes: 33 |
Annoyingly, there's the usual "auto-download roms", which probably makes Kelvin liable of contributory copyright infrigement.
Once I'd like a "simplifying frontend" author to try to tackle the problem of helping the users w.r.t rom management without doing obviously illegal things.
|
|
|
|
Joined: Mar 2001
Posts: 17,217 Likes: 234
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,217 Likes: 234 |
For the limited subset of systems supported, ROM management isn't a thing. You either have the (7)zips in the ROMs folder or you don't. And because of that limited subset, it's probably pretty safe to download the ROMs as well. AppleWin has had the ROMs in the executable for 15 years now, IIRC.
|
|
|
|
Joined: Jun 2001
Posts: 520 Likes: 33
Senior Member
|
Senior Member
Joined: Jun 2001
Posts: 520 Likes: 33 |
It's probably safe with a limited scope such as that one, it would not be safe to do it at mame-scale I suspect.
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
Found a couple of diagnostic disks for the silentype: "Apple II+ Products diagnostic 652-0334.dsk" "Apple II Peripherals diskette 077-0217-A.dsk" I dusted off my old silentype driver and it wasn't working, and I traced it to not initializing an array of doubles. I had code that would compare it to 0.0 and 1.0 and clamp it to that range, so I thought it wouldn't be a problem to leave it unitialized, but if it gets memory that is interpreted as NaN that comparison silently fails. I did learn that you can initialize an array of doubles like this: double myarray[8] = {0.0}; Expecting uninitialized variables to be 0 is a hard habit to break. 8-)
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
In refactoring the code to separate the actual printer part from the interface part, I forgot to hook up the margin switch. The diagnostic program promptly figured this out and had these suggestions: Also there's some strange behavior if I select the head alignment test at the beginning. It seems to print the screen improperly and won't proceed past the firmware test, updating the screen but never finishing. typing Y then N will stop the alignment. testing the firmware never completes with 4 character blocks being constantly updated. If I reset, type IN#6 and select the same test, it will print properly and continue. This is what it's supposed to look like: and now following the reset, the test completes normally. I'd be interested to see if it does this on real hardware, anyone have a real Silentype?
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
I thought I'd see if I can use the steppers.cpp stepper device instead of my own stepper motor code and it looks like the silentype pattern is different from the regular drive table in steppers.cpp. //Standard drive table in steppers.cpp is 2,6,4,5,1,9,8,a //Silentype stepper table is: 3,2,6,4,c,8,9,1 (normal code uses just the full steps) It looks like I can convert the silentype stepper pattern to the "standard" pattern by just swapping bits 0 and 3.
silentype swap 0 3 swap 1 2
0011 3 1010 a 0101 5
0010 2 0010 2 0100 4
0110 6 0110 6 0110 6
0100 4 0100 4 0010 2
1100 c 0101 5 1010 a
1000 8 0001 1 1000 8
1001 9 1001 9 1001 9
0001 1 1000 8 0001 1
But it moves in the "wrong direction". It also appears that reversing the bit order from 3210 to 0123 will change the direction of the stepper. So instead of swaping bits 0 and 3 I can swap just 1 and 2:
u8 silentype_printer_device::bitpattern(u16 val, u8 a, u8 b, u8 c, u8 d)
{
u8 bita = BIT(val,3);
u8 bitb = BIT(val,2);
u8 bitc = BIT(val,1);
u8 bitd = BIT(val,0);
return (bita << a) | (bitb << b)| (bitc << c)| (bitd << d);
}
int silentype_printer_device::update_stepper_delta(stepper_device * stepper, uint8_t pattern)
{
int lastpos = stepper->get_absolute_position();
stepper->update(bitpattern(pattern, 3, 1, 2, 0)); // drive pattern is the "standard" reel pattern with bits 1,2 swapped
int delta = stepper->get_absolute_position() - lastpos;
return delta;
}
void silentype_printer_device::update_cr_stepper(uint8_t hstepper)
{
int delta = update_stepper_delta(m_cr_stepper, hstepper);
if (delta > 0)
{
m_xpos += delta; xdirection = 1;
}
else if (delta < 0)
{
m_xpos += delta; xdirection = -1;
}
}
|
|
|
|
Joined: May 2009
Posts: 2,215 Likes: 382
Very Senior Member
|
Very Senior Member
Joined: May 2009
Posts: 2,215 Likes: 382 |
Please use the existing bitswap macro provided by the core rather than doing it yourself.
|
|
|
|
Joined: Feb 2014
Posts: 1,102 Likes: 173
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,102 Likes: 173 |
so something like bitswap<4>(pattern, 3,1,2,0) instead?
I didn't know bitswap existed, so I learned something 8-) Shows you what I know about c++.
|
|
|
2 members (AJR, Bletch),
354
guests, and
4
robots. |
Key:
Admin,
Global Mod,
Mod
|
|
Forums9
Topics9,320
Posts121,944
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!
|
|
|
|