cpm65
cpm65 copied to clipboard
Writing a new driver in assembly
Hi,
I started working on tty80/screen80 for the Atari. I want it as a loadable driver, but I'm stumbling upon a few problems.
First I started in "asm.com" assembly, but noticed I could not create the needed jump table. .byte <label-1 and .byte >label-1 did not work correctly. The 13 entries for screen:
0C19: 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 4B 0C 0C 0C
0C29: 0C 0C 0C 0C 0C 0C 0C 0C 0C 00
The 3 entries for tty:
0C4F: 61 61 6D 0C 0C 00
The third one here is tty_conout, so that crashes heavily ;) See https://github.com/ivop/cpm65/blob/tty80/apps/a8tty80.asm Adding an extra dummy byte to the table only works if it is equal to the last one before. Adding .byte 0 messes things up and adds both zeroes to the end of the second table.
0C4F: 63 63 63 6F 0C 0C 0C 00
versus
0C4F: 63 63 63 0C 0C 0C 00 00
So, I tried doing it with clang instead. Added a makefile rule to compile .S instead of .c to .o, link to .com was there already, but somehow the resulting cpm65 binary is not relocated correctly. When the code runs, it is as if it was loaded at $0200 instead of higher up ($0c00 on the XL/XE, $1d00 on the 400/800).
0C30: A0 26 LDY #$26
0C32: 20 04 02 JSR $0204
which should be JSR $0C04 (jmp BDOS). See https://github.com/ivop/cpm65/blob/tty80-2/apps/a8tty80.S
I checked the invocations of llvm with the -v flag, and it seems identical to the C version, except for calling cc1as. But there's a relocation flag there, too.
Anyway, I'm stuck. I could do it all in mads, which I know pretty well, but I'd prefer to use the cpm65 tools.
Regards, Ivo
There's clearly an assembler bug, but there should already be makefile support for llvm-based assembler programs --- just drop a .S file into apps and it should work. I'm doing that in https://github.com/davidgiven/cpm65/pull/67/files#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52 and it's working.
Try changing the section name from .text.driver to .text? That's the only thing I can see which is different. The linker script should pick up all .text.* sections, however. The other thing it's worth doing is pushing the binary through OBJDUMP.COM, which will show you precisely where all the relocations are.
I have changed the Makefile back again and it now assembles with the already present rules.
But it still doesn't work. The only relocations done are in the beginning:
Output from OBJDUMP:
ZP: 02 TPA: 03 ZPRELO: 008d TPARELO: 008f
0000 02 . ill
0001 03 . ill
0002 8d 00 4c ..L sta 4c00
TPARELO 0003
0005 00 . brk
0006 00 . brk
0007 20 0b 00 .. jsr 000b
TPARELO 0009
000a 60 ` rts
000b 4c 30 00 L0. jmp 0030
TPARELO 000d
And the rest is fixed to $0200 and beyond.
I recompiled and installed the latest llvm-mos and llvm-mos-sdk (my version was from May), but I still have the same results as mentioned in my previous post, except that objdump does not work correctly anymore. That also happens with the beeb, vic-20 and the apple 2 port. It prints everything on the same line, as if only CR works, but LF doesn't.
Edit: the same happens with stat.c. It seems that the latest version of llvm-mos does not handle \r\n correctly.
Edit2: replacing crlf() by print("\015\012"); does not work either, but cpm_conout(13); cpm_conout(10); does!
Edit3:
static char dat[] = { 13, 10, 0 };
// print(dat);
for (int i=0; i<2; i++)
cpm_conout(dat[i]);
print(dat) does not work, the for loop does. The current llvm-mos seems b0rked.
Edit4: and I cannot install the latest mos-sdk with the compiler from May because of mos-clang: error: the clang compiler does not support '-mcpu=mos65el02'
Anyway, I have it working now with the May version of the compiler and SDK. I had to place the tables and banner explicitly in the data segment. sigh... ;)
Edit: it was more complicated, the defdriver macro switches to the .data segment, so I had to switch back .text for code. Edit2: still not entirely working. Somehow the devices output is messed up now. Edit3: devices output is correct now, too. Had to reserve ZP for jmpdispatch. Finally I can start working on the driver itself and stop edit-bombing you ;-) There is still something different from what happens in the bios code. Tables and the driver description have to be in .text (not .data) otherwise the pointers are not relocated. The bios code has the driver description in .data.
That all sounds utterly bizarre. I wonder if something's changed upstream? llvm-objdump -dr ought to show the ELF relocations (look in .obj)...
Yeah, strange things are happening. With the May compiler, stuff in .data is not relocated (i.e. pointers). I suppose compiling C didn't trigger that somehow, and the bios code is linked to a fixed address. I worked around it by putting stuff in .text instead.
The current HEAD llvm-mos compiler doesn't handle passing string pointers correctly (see stat above). Not sure if it's a cpm65 backend problem or llvm-mos regressed in general. Haven't looked into it in more detail as I was finally motivated to do the 80-columns driver, so I did that. Now I want to finish porting atari8080 and write the 130XE overlay loader.
Okay, I looked into it a bit further, and it seems it is specifically .data that does not get converted from elf to bin. If I put the driver description in .rodata, it works correctly:
038f 19 00 00 ... ora 0000, y
TPARELO 0390
0392 00 . brk
0393 53 S ill
0394 43 C ill
0395 52 45 RE eor (45)
0397 45 4e EN eor 4e
0399 38 8 sec
039a 30 00 0. bmi 039c
Here you can see the reference to the strategy routine is relocated.
But if I put it in .data:
03af 19 02 00 ... ora 0002, y
03b2 00 . brk
03b3 53 S ill
03b4 43 C ill
03b5 52 45 RE eor (45)
03b7 45 4e EN eor 4e
03b9 38 8 sec
03ba 30 00 0. bmi 03bc
it is not.
I don't see any difference in the relocation tables in the .elf files other than the fact that they are in .data or .rodata:
RELOCATION RECORDS FOR [.rodata]:
OFFSET TYPE VALUE
0000058f R_MOS_ADDR16 drv_screen80_strat
vs
RELOCATION RECORDS FOR [.data]:
OFFSET TYPE VALUE
000005bb R_MOS_ADDR16 drv_screen80_strat
But I noticed this:
Driver description in .data:
.obj/a8tty80drv.com.elf: file format elf32-mos
Program Header:
LOAD off 0x000000b4 vaddr 0x00000200 paddr 0x00000200 align 2**0
filesz 0x00000628 memsz 0x00000628 flags rwx
UNKNOWN off 0x000006dc vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000a74 memsz 0x0000018c flags r--
UNKNOWN off 0x00001150 vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000e70 memsz 0x00000e70 flags r--
Driver description in .rodata:
.obj/a8tty80drv.com.elf: file format elf32-mos
Program Header:
LOAD off 0x000000b4 vaddr 0x00000200 paddr 0x00000200 align 2**0
filesz 0x00000628 memsz 0x00000628 flags rwx
UNKNOWN off 0x000006dc vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000a80 memsz 0x00000198 flags r--
UNKNOWN off 0x0000115c vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000e70 memsz 0x00000e70 flags r--
Notice that the second to last section is smaller in .data compared to .rodata.