|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
I was reading the manual for the Fingerprint G+ card and it seemed really similar to the Grappler+ manual. Fingerprint G+ card manual / Grappler + manual:
|
|
|
|
Joined: Mar 2001
Posts: 17,234 Likes: 260
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,234 Likes: 260 |
A lot of cards back then were designed and documented by independent engineering firms for whoever did the manufacturing (much like how a lot of video cards today use the Nvidia or AMD reference design), and they likely would keep them pretty similar across customers. That's a good catch though!
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
I was able to get the fingerprint g+ to print something in color. The fingerprint g+ supports the epson jx-80. it also supports printing the lo-res screen:
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
The fingerprint g+ has a 16k rom which has an interesting banking scheme: To appear in the 2k window at C800-CFFF the 16K rom has 8 2k banks. Writes to C088,x will set the bank. The first bit of code at C800 and C100 will reset the bank to 0 so it will always start with bank 0 no matter which bank is initially selected. c800: 48 pha
c801: a9 00 lda #$00
c803: 99 88 c0 sta $c088, y
and this code gets repeated at the beginning of every bank. What's cool is that the bank number of the current bank is at CFFC. So if we want to execute some code in another bank and come back to our current bank, we just read CFFC, store it somewhere, then write that value back to C088,y. 0000-07ff is bank 00
0800-0fff is bank 80
1000-17ff is bank 40
1800-1fff is bank c0
2000-27ff is bank 20
2800-2fff is bank a0
3000-37ff is bank 60
3800-3fff is bank e0
reading from cffc will tell you the current bank:
hexdump fingerprint_gplus_27c128.u1 | grep "000.[7f]f0"
00007f0 c080 eaea 80ad 9903 c088 ff60 ff00 0fff <=== bank = 00
0000ff0 c080 eaea 80ad 9903 c088 ff60 ff80 0fff <=== bank = 80
00017f0 c080 eaea 80ad 9903 c088 ff60 ff40 0fff <=== bank = 40
0001ff0 c080 eaea 80ad 9903 c088 ff60 ffc0 0fff
00027f0 c080 eaea 80ad 9903 c088 ff60 ff20 0fff
0002ff0 c080 eaea 80ad 9903 c088 ff60 ffa0 0fff
00037f0 c080 eaea 80ad 9903 c088 ff60 ff60 0fff
0003ff0 c080 eaea 80ad 9903 c088 ff60 ffe0 0fff
bit 7 is +800 8
bit 6 is +1000 4
bit 5 is +2000 2
ROM_START(fingerprint_gplus_rom)
ROM_REGION(0x4000, "prom", 0)
ROM_LOAD( "fingerprint_gplus_27c128.u1", 0x0000, 0x4000, CRC(90bdec85) SHA1(7218016ad00b2d65a3ff473b6950d1e6e047f717) )
ROM_END
void a2bus_fingerprint_gplus_device::write_c0nx(u8 offset, u8 data)
{
switch (offset)
{
...
case 8U:
bank_base_address = (data & 0x80 ? 0x800 : 0) + (data & 0x40 ? 0x1000 : 0) + (data & 0x20 ? 0x2000 : 0);
printf("bank base address = %x\n",bank_base_address);
}
}
uint8_t a2bus_fingerprint_gplus_device::read_c800(uint16_t offset)
{
return m_prom[offset + bank_base_address];
}
and the code for c100 is at offset 3000 + 100 * slot number. d71c: a2 c7 ldx #$c7 c7 is slot address
d71e: a0 70 ldy #$70 70 is slot offset
d720: 84 26 sty $26
d722: 8e f8 07 stx $07f8
d725: a9 00 lda #$00
d727: 8d ff cf sta $cfff
d72a: 99 88 c0 sta $c088, y reset the bank to zero f = io.open("fingerprint_gplus_27c128.u1") a=f:read("*a") print(a:len()) for i=0,a:len()-1 do c = a:byte(i+1) if (i%64 == 0) then print() io.write(string.format("%4x",i)..": ") end c = c % 128 if c>=32 and c<=126 then io.write(string.char(c)) else io.write(".") end if c==0x1b then io.write("ESC") end end print()
for j=0,6 do o0=0x3100 o1=0x3100 + j*0x100 for i=0,255 do if a:byte(i+1+o0) ~= a:byte(i+1+o1) then print(i,string.format("%x",i+o1),string.format("%x",a:byte(i+1+o0)),string.format("%x",a:byte(i+1+o1))) end end end
29 321d c1 c2
31 321f 10 20
29 331d c1 c3
31 331f 10 30
29 341d c1 c4
31 341f 10 40
29 351d c1 c5
31 351f 10 50
29 361d c1 c6
31 361f 10 60
29 371d c1 c7
this same pattern gets repeated at offset 3900 > for j=0,6 do o0=0x3900 o1=0x3900 + j*0x100 for i=0,255 do if a:byte(i+1+o0) ~= a:byte(i+1+o1) then print(i,string.format("%x",i+o1),string.format("%x",a:byte(i+1+o0)),string.format("%x",a:byte(i+1+o1))) end end end
29 3a1d c1 c2
31 3a1f 10 20
29 3b1d c1 c3
31 3b1f 10 30
29 3c1d c1 c4
31 3c1f 10 40
29 3d1d c1 c5
31 3d1f 10 50
29 3e1d c1 c6
31 3e1f 10 60
29 3f1d c1 c7
31 3f1f 10 70
comparing the two banks shows a few differences.
> for j=0,6 do o0=0x3100 o1=0x3900 + j*0x100 for i=0,255 do if a:byte(i+1+o0) ~= a:byte(i+1+o1) then print(i,string.format("%x",i+o1),string.format("%x",a:byte(i+1+o0)),string.format("%x",a:byte(i+1+o1))) end end end
129 3981 fe 27
131 3983 fe 0
193 39c1 fe 27
195 39c3 fe 0
29 3a1d c1 c2
31 3a1f 10 20
129 3a81 fe 27
131 3a83 fe 0
193 3ac1 fe 27
195 3ac3 fe 0
29 3b1d c1 c3
31 3b1f 10 30
129 3b81 fe 27
131 3b83 fe 0
193 3bc1 fe 27
195 3bc3 fe 0
It seemed to work fine mapping offset 3000 + 100 * slotno() into C100 u8 a2bus_fingerprint_gplus_device::read_cnxx(u8 offset)
{
return m_prom[offset+0x3000+0x100*slotno()];
}
and I think it's very similar to the grappler plus with regards to reading c080 for status, writing c080 for outputting data to the printer. it writes c088 to change the bank. it reads c08f to read the DIP switches on the card. Only switches 1-6 are used, 7-8 are unused. and it's the inverted bit pattern from the manual so 1 will be zero and 0 will be 1. SW6 = b0, SW5 = b1, SW4 = b2, SW3 = b3, SW2 = b4, SW1 = b5
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
So the fingerprint g+ is supposed to support regular hi-res: which looks fine. It's also supposed to support double hi-res and lo-res, however color 15 white prints as black for some reason. (doing some experiments changing the cf4b table while it's printing) There's a table at cf4b that seems to control the printed colors. There's a 2 color dither, offset 0-15 low nibble is color a and 16-31 low nibble is color b. It's actually quite clever, bit 3 is black, bit 2 is magenta, bit 1 is cyan, bit 0 is yellow. So if I take entries 15 and 31 for color 15 = white and change them from 8F 8F to 0 and 0 then the print looks normal: It looks even better if I do some color correction in gimp to more closely match the screen colors:
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
Since I've been studying a2 printer cards, I came across this article about a guy who decided to make his own printer card, it's a fun read: My tipping point came the day I decided to add a printer. I saved up $1,000 and headed down to the local Apple store in Santa Barbara to buy a Paper Tiger dot matrix printer along with the add-on board to connect it to the computer.
Damn. They wanted $185 for that stupid little board; nearly one quarter of the price of the printer itself. And believe me, I had spent enough time at Radio Shack to know there wasn’t much more than a few dollars worth of parts on it.
It was right then I decided I’d design and sell a competing card. https://medium.com/predict/going-toe-to-toe-with-steve-jobs-a5a2ed686ab5
|
|
|
|
Joined: Feb 2021
Posts: 30
Member
|
Member
Joined: Feb 2021
Posts: 30 |
Wow! I enjoy to read that topics since I am new to this MAME forum. I am now learning a lot about MAME. You are able getting Epson LX (or AP2000) printer emulators working. Are you plan to implement more printer emulators like Gemini 10/10X, older Epson MX/FX (running in 8048 microcontroller) with Graftax-80 (designed for TRS-80 computers) and plotters like ALPS DPG1302 plotter? I love to see printouts in color (Epson JX-80 emulator) but I can't find JX80 in MAME emulator list.
|
|
|
|
Joined: Jun 2001
Posts: 526 Likes: 37
Senior Member
|
Senior Member
Joined: Jun 2001
Posts: 526 Likes: 37 |
The #1 question is always "are dumps of every rom, including internal, present in the device available?". If no, then no. If yes, then problably.
|
|
|
|
Joined: Feb 2004
Posts: 2,603 Likes: 307
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,603 Likes: 307 |
I’ve added the Orange Micro Buffered Grappler+. It’s kind of like a Grappler+ and Bufferboard combined, but there are some differences. Firstly, it has no host interrupt output, so the C0nX write addresses for interrupt enable/disable aren’t implemented, and bit 7 of C0nX read returns the state of SW1-1 (forced 7-bit mode). Secondly, forced 7-bit mode isn’t implemented by pulling a data line low with the DIP switch, the ROM driver checks the switch value and clears the bit in software if necessary.
However, the microcontroller dump is bad. With 16K buffer RAM (four 6164 chips installed), it doesn’t work. The byte at 0x179 is 0xff (mov a,r7) when it should be 0xfd (mov a,r5). There could be other bad bits in the ROM as well, I don’t think there’s a way to test it.
|
|
|
|
Joined: Feb 2014
Posts: 1,124 Likes: 193
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,124 Likes: 193 |
Hi Vas, Your buffered grappler driver is really nice and elegant. I could never do that in a million years 8-) Tribute! I wanted to see the self test for fun so I added a little bit of code to simulate the reset line controlled by an ioport and discovered another corrupt byte: This is surely incorrect, but it seems to work ok.
INPUT_PORTS_START(bufgrapplerplus)
PORT_INCLUDE(grapplerplus)
PORT_START("CNF")
PORT_CONFNAME(0xff, 0x00, "RAM Size")
PORT_CONFSETTING( 0xfc, "16K (2 chips)")
PORT_CONFSETTING( 0xf0, "32K (4 chips)")
PORT_CONFSETTING( 0x00, "64K (8 chips)")
PORT_START("Reset")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Reset") PORT_CODE(KEYCODE_DEL_PAD)
INPUT_PORTS_END
added this in device_add_mconfig:
m_mcu->p2_in_cb().set(FUNC(a2bus_buf_grapplerplus_device::mcu_p2_r));
u8 a2bus_buf_grapplerplus_device::mcu_p2_r()
{
int retval = (m_mcu_p2 & 0x7f) | 0x4 | ((machine().time().as_double() < (2.0/60)) ? 0x0 : (ioport("Reset")->read() ? 0x80 : 0x0)); // bit 2 is always 1 since +5 I think
printf("retval = %x time=%f\n",retval,machine().time().as_double());
return retval;
}
If you want to see the self test every time, make the above test ((machine().time().as_double() < 3.0) since the input system gets updated every frame it won't see the key down until .0168 of time (1/60th second) so that's why I've got the 2.0/60 in the test retval = ee time=0.000298 retval = ee time=0.001224 ... retval = ee time=0.013711 retval = ee time=0.015272 retval = 6e time=0.016833 <<< input system picks up key down after 1 frame and ee --> 6e retval = 6e time=0.017728 0:330: 0a in a,p2 get value of p2
0:331: f2 47 jb7 $347 bit 7 = reset 'reset active low so jump to 347 and set the flag if reset isn't pressed
0:333: ff mov a,r7 -- I think r6 and r5 are a "countdown timer" <<<<< this should be fe instead of ff mov a,r6 since the jnz responds to the accumulator only
0:334: ce dec r6
0:335: 96 38 jnz $338 test if r6 is nonzero
0:337: cd dec r5
0:338: fd mov a,r5
0:339: 4e orl a,r6
0:33a: 96 00 jnz $300 if r5/r6 are nonzero then jump to refresh ram
0:33c: 0a in a,p2 (once we get here, we keep spinning until the reset button is released)
0:33d: f2 41 jb7 $341
0:33f: 64 3c jmp $33C -- spin again
0:341: 76 4f jf1 $34F -- flag1 set, jump to 34f
0:343: c5 sel rb0
0:344: 34 8e call $18E self test
0:346: d5 sel rb1
0:347: a5 clr f1
0:348: b5 cpl f1 set f1 64k: 32k: 16k: Sorry about the bad dump, I tried to get a good dump. I dumped it 3 times and they were all identical. Some fun testing with Zoom Grafix: taking the printer offline and printing 2 x 3 will go completely in the buffer. 3x3 will get most of the way down before it has to wait. If you set the left margin to zero you almost get to the bottom. (3*280+6) * (3*192/7) = 69614 bytes so a little bigger than 64k. Start 3x3 printout: Buffer full, has to wait about 3/4 way down:
|
|
|
4 members (ameath, Dorando, Kale, 1 invisible),
224
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!
|
|
|
|