I just purchased a new HW goodie for my classic Amiga 500. A clockport adapter and a SilverSurfer serial card that allows high baudrates (e.g. 115200 baud) on this machine without generating too much CPU load.
HW installation was fairly easy, but with the software the trouble began… The supplied drivers does not run on an Amiga 500 but only on an A1200 🙁 Being a real retro hacker I had a look at the driver binary, disassembled it and found out that the code could be easily patched to run on an A500, too.
Now it works like a charm even on the 680000 machines. Here try yourself: silversurfer104-a500.zip
If you want to know how this was done… then read on… Be warned: technical details ahead 😉
1. Take a close look at the binary
First of all I did a disassembly of the original driver binary. As the Amiga binaries are in the LoagSeg()able Hunk Format you need a tool that can cope with this type of files.
Fortunately, in my amitools Project I am developing a tool called hunktool that allows to inspect those files. With the help of the dissassemblers vda68k or m68k-elf-objdump from the gnu toolchain (here created like described in the 68k AROS project) it even can disassemble the code segments… Since my tools are written in Python 2.x they run almost everywhere…
On my Mac I did a:
> hunktool info -A silversurfer.device > surfer.txt
Voila! A full disassembly nicely annoted with relocations was generated. You get something like this:
silversurfer.device TYPE_LOADSEG header (segments: first=0, last=0, table size=1) #000 CODE size 000037f4 file header @00000018 data @00000020 reloc absreloc32 #1 To Segment #0: 23 entries 00000000 70ff moveq #-0x1,d0 00000002 4e75 rts 00000004 7000 moveq #0,d0 00000006 4e75 rts 00000008 4afc illegal 0000000a 0000 0008 ori.b #0x8,d0 ; absreloc32: self: 00000008 0000000e 0000 37f2 ori.b #-0xe,d0 00000012 8002 or.b d2,d0 00000014 0305 btst d1,d5 00000016 0000 0024 ori.b #0x24,d0 ; absreloc32: self: 00000024 0000001a 0000 0081 ori.b #-0x7f,d0 ; absreloc32: self: 00000081 0000001e 0000 00c8 ori.b #-0x38,d0 ; absreloc32: self: 000000c8 00000022 0000 7369 ori.b #0x69,d0 00000026 6c76 bge.b 0x9e 00000028 6572 bcs.b 0x9c 0000002a 7375 moveq #0x75,d1 0000002c 7266 moveq #0x66,d1 0000002e 6572 bcs.b 0xa2 00000030 2e64 movea.l -(a4),sp 00000032 6576 bcs.b 0xaa 00000034 6963 bvs.b 0x99 00000036 6500 5369 bcs.w 0x53a1 0000003a 6c76 bge.b 0xb2 0000003c 6572 bcs.b 0xb0 0000003e 5375 7266 subq.w #0x1,(0x66,a5,d7.w*2)
Now its time to analyse the code and to refresh your amiga knowledge. Decode resident structures, library calls and look out for memory accesses in the range of the clockport… Have a look at Inside Silver Surfer and you’ll find out we have to look for addresses like $d80001 in the driver code…
For decoding library calls and data structures I wrote two additional tools in amitools: fdtool and typetool. The first on you run with a library FD file from your Commodore NDK and it gives you details about function calls in a library:
> ./fdtool NDK_3.1/Includes\&Libs/fd/exec_lib.fd NDK_3.1/Includes&Libs/fd/exec_lib.fd base: _SysBase #0001 30 0x001e Supervisor [userFunction,a5] #0002 72 0x0048 InitCode [startClass,d0][version,d1] #0003 78 0x004e InitStruct [initTable,a1][memory,a2][size,d0] #0004 84 0x0054 MakeLibrary [funcInit,a0][structInit,a1][libInit,a2][dataSize,d0][segList,d1] #0005 90 0x005a MakeFunctions [target,a0][functionArray,a1][funcDispBase,a2] #0006 96 0x0060 FindResident [name,a1] #0007 102 0x0066 InitResident [resident,a1][segList,d1] #0008 108 0x006c Alert [alertNum,d7] #0009 114 0x0072 Debug [flags,d0] ...
Now its very easy to decode a jsr -off(a6) library call (see second column for offsets!). typetool gives you the offset of data structures (Unfortunately, not all NDK datatypes are available in this tool right now):
> ./typetool ExecLibrary @0000 ExecLibrary { @0000 Library { @0000 Node { 0000 @0000/0000 +0004 Node* ln_Succ (ptr=True, sub=False) 0001 @0004/0004 +0004 Node* ln_Pred (ptr=True, sub=False) 0002 @0008/0008 +0001 UBYTE ln_Type (ptr=False, sub=False) 0003 @0009/0009 +0001 BYTE ln_Pri (ptr=False, sub=False) 0004 @0010/000a +0004 char* ln_Name (ptr=True, sub=False) @0014 =0014 } lib_Node 0005 @0014/000e +0001 UBYTE lib_Flags (ptr=False, sub=False) 0006 @0015/000f +0001 UBYTE lib_pad (ptr=False, sub=False) 0007 @0016/0010 +0002 UWORD lib_NegSize (ptr=False, sub=False) 0008 @0018/0012 +0002 UWORD lib_PosSize (ptr=False, sub=False) 0009 @0020/0014 +0002 UWORD lib_Version (ptr=False, sub=False) 0010 @0022/0016 +0002 UWORD lib_Revision (ptr=False, sub=False) 0011 @0024/0018 +0004 APTR lib_ldString (ptr=False, sub=False) 0012 @0028/001c +0004 ULONG lib_Sum (ptr=False, sub=False) 0013 @0032/0020 +0002 UWORD lib_OpenCnt (ptr=False, sub=False) @0034 =0034 } LibNode ...
Furthermore, you can use hunktool to have a look at a hexdump of the segments, too.
> ./hunktool info -x silversurfer.device silversurfer-hack.device TYPE_LOADSEG header (segments: first=0, last=0, table size=1) #000 CODE size 000037f4 file header @00000018 data @00000020 00000000: 70 ff 4e 75 70 00 4e 75 4a fc 00 00 00 08 00 00 p<FF>Nup.NuJ<FC>...... 00000010: 37 f2 80 02 03 05 00 00 00 24 00 00 00 81 00 00 7<F2><80>......$...<81>.. 00000020: 00 c8 00 00 73 69 6c 76 65 72 73 75 72 66 65 72 .<C8>..silversurfer 00000030: 2e 64 65 76 69 63 65 00 53 69 6c 76 65 72 53 75 .device.SilverSu 00000040: 72 66 65 72 20 42 6f 61 72 64 2d 00 20 55 6e 69 rfer Board-. Uni 00000050: 74 00 00 00 20 52 00 00 20 57 00 00 53 69 6c 76 t... R.. W..Silv 00000060: 65 72 53 75 72 66 65 72 20 6c 69 67 68 74 73 70 erSurfer lightsp 00000070: 65 65 64 20 53 65 72 76 65 72 00 00 24 56 45 52 eed Server..$VER 00000080: 3a 53 69 6c 76 65 72 53 75 72 66 65 72 20 32 2e :SilverSurfer 2. 00000090: 31 30 34 20 28 31 33 2e 31 31 2e 30 30 29 0d 0a 104 (13.11.00).. 000000a0: 28 63 29 20 31 39 39 31 2d 45 56 45 52 20 62 79 (c) 1991-EVER by 000000b0: 20 56 4d 43 20 48 61 72 61 6c 64 20 46 72 61 6e VMC Harald Fran 000000c0: 6b 0d 0a 0d 0a 00 00 00 00 00 00 f4 00 00 00 d8 k..........<F4>...<D8> ...
With the help of these tools and my trusty old Developer manuals I soon found out everything I need to know about the driver. See my partially annotated disassembly here: silversurfer104-disasm.txt
Code Analysis
The interesting part looking for a silver surfer HW is here:
; ----- detecte silver surfer ----- 00002b9c 48e7 7ffe movem.l d1-d7/a0-a6,-(sp) 00002ba0 2f0e move.l a6,-(sp) 00002ba2 2c6e 003c movea.l 0x3c(a6),a6 ; a6 = ExecBase 00002ba6 43fa 0be8 lea 0x3790(pc),a1 ; a1 = "card.resource" 00002baa 4eae fe0e jsr -0x1f2(a6) ; OpenResource [resName,a1] 00002bae 2c5f movea.l (sp)+,a6 ; libaddr 00002bb0 4a80 tst.l d0 00002bb2 6648 bne.b 0x2bfc ; ok! -> look for surfer
Aha! It looks for card.resource and if this is found then try to detect one. This one works like a charm on an A1200 with a card slot but not on A500 where this resource is missing. So on my machine this driver will never try to even look for the HW…
Ok, we need to patch this in order to have the driver look for my surfer… One way of doing this might be to replace the bne.s branch with a bra.s. I chose another option: just replace the resource name and use ciaa.resource instead of card.resource 😉 This resource is available on the A500, too 😉 A simple string replace in the driver binary does the trick!
Now the driver allows to open unit 0 on my machine! Yehaw!!
Unfortunately, it still crashes when trying to actually transfer data with it… 🙁
While scanning the disassembly I soon found some long branches (bra.l, bne.l, …) that are only available on cpus starting with 68020. So my A500 with a 68000 only sees a bogus (odd destination address) byte branch and crashes…
Damn! Its 68020 code… But as the init already works I need to find out how many 68020 instructions are actually used.. Again I use hunktool to find this out: It allows to use m68k-elf-objdump to do the disassemlby and this allows me to select the cpu type. So I did a dissassembly for the 68000 and the 68020 and simply diff’ed the result to see the 68020 portions:
> ./hunktool info -A -o -c 68000 silversurfer.device > ss000.txt > ./hunktool info -A -o -c 68020 silversurfer.device > ss020.txt > diff ss000.txt ss020.txt 307,308c307 < 0000040a 61ff bsrs 0x40b < 0000040c 0000 02a6 orib #-90,%d0 --- > 0000040a 61ff 0000 02a6 bsrl 0x6b2 310,311c309 < 00000414 61ff bsrs 0x415 < 00000416 0000 029c orib #-100,%d0 ..
Aha! Its only the long branches… And we are lucky ones: the binary is only 16k and so each long branch could be converted into a 68000 compatible word branch… The spare word in each instruction will then be filled with a NOP opcode… So I could patch the binary in place and do not need to relocate anything… Phew!
The branch conversion actually needs to clear the branch offset in the first word (0xff -> 00), remove the next word and keep the lower branch offset. Then add a NOP opcode word. This could be done by hand, but we are hackers so I wrote a little Python script to perform the patch: fix_bsrl.py
Just call it with the offsets to patch and it will do the job… (If you wonder where the global offset 32 in the -a switch comes from: Its the begin of the code segment in the hunk file. You can find the value in the output of hunktool: look for CODE data @20)
> grep bsrl ss020.txt > offsets > hacks/fix_bsrl.py -a 32 silversurfer.device offsets OK: 0000042a distance: 678 OK: 00000434 distance: 668 OK: 00000e80 distance: 6862 OK: 0000106a distance: 236 OK: 000010a0 distance: 62 OK: 0000110a distance: 26 OK: 0000111a distance: 10 OK: 00002288 distance: 1930 OK: 000026e8 distance: 614 OK: 000028a2 distance: 172 writing 'silversurfer.device.patched'... done
Ok! Patch complete…
The driver now works on my A500 without any problems and I can do SLIP via AmiTCP with 115200 Baud resulting in approx. 8 KiB/s FTP transfer rate…
That’s it… I hope you enjoyed my little archeological excursion in hacking classic Amiga driver code…
Will it run with HyperPort 1200 ?
You are my HERO!!!
I have an A500, and messed around for a month trying to get the PortJNR serial device working (never did – I could never get it to boot with the device attached). I then bought the Silver Surfer, and although I did not have any problems booting, I couldn’t get AExplorer to work with the silversurfer.device.
THEN I saw your post. I downloaded the device, installed it on my A500, and PRESTO – I can not transfer files back and forth at 115200 (compared to the previous max of 38400).
THANK YOU!!!