Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.8xp file produced by ZCC cannot run under TI-OS on TI-84+ #1622

Open
siraben opened this issue Oct 29, 2020 · 23 comments
Open

.8xp file produced by ZCC cannot run under TI-OS on TI-84+ #1622

siraben opened this issue Oct 29, 2020 · 23 comments

Comments

@siraben
Copy link

siraben commented Oct 29, 2020

Given the following C program and Makefile, building succeeds but when I try to run it on the TI-84+ calculator (emulated) under TI-OS, I get an ERR: INVALID file. Looks like the binary needs to have $bb $6d prefixed to it before the conversion to .8xp happens.

#include <stdio.h>

int main()
{
  puts("hello");
  return 0;
}
all:
    zcc +ti8x -startup=10 -create-app hello.c -o hello
@siraben siraben changed the title Invalid .8xp file produced by ZCC .8xp file produced by ZCC cannot run under TI-OS on TI-84+ Oct 29, 2020
@zx70
Copy link
Member

zx70 commented Nov 4, 2020

this is an old, never ending topic 😁
I tend to prefer to evolve appmake and keep all the possible output variants. Could an option, say, named "-Cz--bb6d" suffice.?

@siraben
Copy link
Author

siraben commented Nov 8, 2020

Sure, that would work, but I thought that appmake would generate the .8xp file properly?

@zx70
Copy link
Member

zx70 commented Nov 8, 2020

with the ti83plus formats, we had claims about the right way to create the application since forever. I think that depending on the transfer tools/emulators in use, those 2 bytes are necessary or superflous (perhaps addec by the tool itself?).. if we change it, someone else will complain.
So, I checked the code and such workaround is in place already, and I forgot about that :)

please try by adding:
-Cz--altfmt
to your build command line

@zx70
Copy link
Member

zx70 commented Dec 31, 2020

@siraben ..did it work?

@empathicqubit
Copy link
Contributor

empathicqubit commented Dec 4, 2022

If I try with

zcc +ti8x -subtype=mirage -startup=2 -Cz--altfmt -Cz--comment=what -create-app world.c

It successfully transfers to Wabbit, but there is weird junk in the name, and it does not appear in Mirage. However, if I try the same command, but edit the crt0 to include the extra bytes:

IF (startup=2)
	DEFINE MirageOS			;Used by greyscale interrupt etc.
	DEFINE NOT_DEFAULT_SHELL	;Else we would use Ion
	;org	$9D95
	org	$9D93
	defb         $BB,$6D

It seems to execute correctly in Mirage but still has the weird junk in the name. If I remove the switch with the above edit, Wabbit refuses to transfer the file again. If I use binpac8x with the above edit, that also works and there is no junk in the name. If I use binpac8x without the edit, then it does not appear in Mirage.

@empathicqubit
Copy link
Contributor

empathicqubit commented Dec 4, 2022

This is a really cool tool btw. Is it possible to attach a debugger to an emulator using the gdb stuff? I was going to write my own debugger for VSCode if there wasn't anything, but I'm still trying to figure out what the best tools are for that. There are already gdb extensions for VSCode so if it was possible to use one of those then I probably don't need to do anything.

@zx70
Copy link
Member

zx70 commented Dec 4, 2022

@empathicqubit
Copy link
Contributor

empathicqubit commented Dec 4, 2022

Could there be a different toggle as you suggested, because altfmt doesn't do it all the way, and it's a bit awkward to have to dig around the crt.

@empathicqubit
Copy link
Contributor

If I figured out which files worked with my calculator would that be helpful? I don't have a computer link cable for it but I can get one.

@zx70
Copy link
Member

zx70 commented Dec 7, 2022

I probaby should simply look for the wabbit emulator, binpac8x and try it myelf.

@empathicqubit
Copy link
Contributor

This is what I'm seeing with TI Connect:

MirageOS (-startup=2 -subtype=mirage) With crt0 edit Without crt0 edit
No additional switches TI Connect accepts file, but transfer fails (8C010001) TI Connect accepts file, but transfer fails (8C010001)
-Cz--altfmt TI Connect rejects file (incompatible type) TI Connect rejects file (incompatible type)
binpac8x TI Connect transfers file, appears in Mirage and runs TI Connect transfers file, does not appear in Mirage

@SimonEast
Copy link

SimonEast commented Jan 20, 2023

I'm also attempting to compile a plain Asm( version of an 8XP file and having it fail. The reason is because the binary format is incorrect/corrupted. There are a few errors.

A few weeks ago I did some deep diving into the 8XP binary format, using numerous working source files to properly understand it and document it. You can find the structure listed here:

https://gist.github.com/SimonEast/244a0fd04526ea1acbec2e2ceb2e7924

By loading the KSY file and an 8XP file into the free Kaitai IDE you can inspect each byte and field more easily. (Well, you can on normal 8XP files, but for these corrupt ones I had to comment out the body field so that parsing would actually succeed.) From this structure I can tell which fields are not being compiled correctly:

Screenshot - Fri 20 Jan 23 , 11_49_20 pm

  • bodyAndChecksumLength and bodyAndChecksumLength2 should both be 2135, exactly 17 less than metaAndBodyLength.
  • isArchived should be either 0x00 for non-archived, or 0x80 for archived. I don't think 0x08 is a valid value.
  • The bodyLength is MUCH too big.

Furthermore, the first two bytes of the program body, immediately after the metaData section shown above should be 0xBB6D, but I don't think this occurs unless you run the command to manually add that. -startup=10 should do this automatically, and maybe even for some of the other target formats too?

This same file structure applies to both TI-BASIC 8XP files, and Assembly 8XP files, with the only difference being that Assembly files have the 0xBB6D as the first two bytes of the body, which tells the calculator that it's assembly, not BASIC.

It would be good to get this fixed up. I have a decent idea of the binary format, but I'm not very familiar with z88dk, having only tried it out this evening for the first time; so I'm not sure how to make these adjustments.

In case it helps, here are two sample files, one properly structured file compiled from Assembly by Brass, and one broken one from z88dk:

P.S. The Z88DK "Hello world" example is quite large, at over 2,000 bytes. Why so large for such a short file?

@SimonEast
Copy link

SimonEast commented Jan 20, 2023

I managed to get a Z88DK "hello world" example working correctly by passing it through the Brass assembler, as a workaround.

Step 1: Compile with z88dk

zcc +ti8x -startup=10 -lm -o hello hello-world\hello.c

Step 2: Create a short ASM file for Brass to read (such as hello.asm, in the same folder), and pass in the binary file you compiled in step 1:

; This tells the assembler what format to output the file in
; We don't want plain bytecode, we want it in 8XP format
; that the calculator can read.
; See https://benryves.com/bin/brass/ and click .binarymode
.binarymode TI8X

; This needs to be at the start of most ASM programs
; It defines where to start counting memory from
; Is it needed in this case for a precompiled binary file? Not sure.
.org 9D93h

; This adds the "AsmPrgm" token to the start of the file 
; which tells the OS not to execute this as as TI-BASIC
; but as assembly instead
.db BBh,6Dh

; Here is the filename of your file compiled from Z88DK
.incbin "hello"

Step 3: Compile with Brass

brass hello.asm hello.8xp

The resulting file has the correct binary header structure, and loads and runs correctly under Wabbitemu using Asm(prgmHELLO), with no shells required. Haven't yet tested on my actual TI-84+, but I suspect it's more likely to work.

@empathicqubit
Copy link
Contributor

empathicqubit commented Jan 20, 2023

I am doing something like this in my Makefile:

cat <( echo -ne "\xbb\x6d" ) build/program.bip > program.bin

And then passing that to binpac8x. It might be a simpler workaround than including another compiler in the mix.

https://github.com/empathicqubit/ti8xp-c-template

I've made some improvements to this in a private project which I haven't ported over yet.

I've also been wondering why z88dk seems so large. I gave up using C and started writing my project completely in assembly for now, still with z88dk so I can use GDB debugging with Wabbit.

@empathicqubit
Copy link
Contributor

The reason the hello world is so big is because it uses printf. If you change it to use cputs() then the bin file is only 414 bytes.

@SimonEast
Copy link

I am doing something like this in my Makefile...

I'm not fluent enough in makefiles to understand exactly what this is doing. Are you passing the C code into z88dk first, then adding the 2 AsmProg token bytes, and then into binpac8x? Anyway, thanks for the tip.

I've also been wondering why z88dk seems so large. I gave up using C and started writing my project completely in assembly for now, still with z88dk so I can use GDB debugging with Wabbit.

Interesting. I was exploring C after finding assembly reasonably fast and performant, yet tedious to do things like simple loops, and nested loops. But I may switch between the two. I like that with z88dk you can inject pure assembly into a C function, effectively utilizing them both.

I don't know anything about GDB debugging, but it sounds like it might be helpful. I haven't figured out how WabbitEmu's default debugger works as yet. But it would be nice to get insight into what the program is doing. You can still use GDB with your pure assembly program in WabbitEmu?

@empathicqubit
Copy link
Contributor

I'm not fluent enough in makefiles to understand exactly what this is doing. Are you passing the C code into z88dk first, then adding the 2 AsmProg token bytes, and then into binpac8x? Anyway, thanks for the tip.

That's right. The echo just adds the two bytes to z88dk's bin output (I called the file bip for no particular reason)

Interesting. I was exploring C after finding assembly reasonably fast and performant, yet tedious to do things like simple loops, and nested loops. But I may switch between the two. I like that with z88dk you can inject pure assembly into a C function, effectively utilizing them both.

Yes, that also works. I might switch to doing that instead, just being careful not to import anything from z88dk.

I don't know anything about GDB debugging, but it sounds like it might be helpful. I haven't figured out how WabbitEmu's default debugger works as yet. But it would be nice to get insight into what the program is doing. You can still use GDB with your pure assembly program in WabbitEmu?

GDB works with pure assembly. It's not quite as helpful as it is with C, but it has the labels and such. So with z88dk I usually start with break _main and trace on, and then I can work from there. I like z88dk's interface better than Wabbit's GUI, which sometimes gets confusing with the way it addresses things.

GDB support is a feature I added to Wabbit, so it's not available on Sputt's release yet. There's also the on-calculator GDB over serial cable, but I would say that it's a bit too wacky to be helpful and I would just turn it off. The problem is since there's no direct CPU access you can't do instruction stepping very easily.

@empathicqubit
Copy link
Contributor

These releases collect some of the changes I've made to Wabbit: https://github.com/empathicqubit/wabbitemu/releases

@empathicqubit
Copy link
Contributor

You'll also want to grab the nightly of z88dk, because GDB wasn't working on Windows in the release build:

http://nightly.z88dk.org/z88dk-win32-latest.zip

@suborb
Copy link
Member

suborb commented Jan 22, 2023

I've also been wondering why z88dk seems so large. I gave up using C and started writing my project completely in assembly for now, still with z88dk so I can use GDB debugging with Wabbit.

I suspect this is because we tend to provide an environment that's suitable for running portable C code - for example stdio is setup and available. When writing games it's not so useful, so there are ways to remove it.

To take the hello world case, there's a few things that can be done to trim things down:

  1. Define the printf formatters: #pragma printf "" (world.c is an odd case since no formatters are used, so we fallback onto the default which pulls in a common set)
  2. Disable stdio: -pragma-define:CRT_ENABLE_STDIO=0 and switch printf to printk: https://github.com/z88dk/z88dk/wiki/WritingOptimalCode#classic-library
  3. As noted above, switching the printf/printk to cputs()
  4. If you don't care about BSS memory being initialised add: -pragma-define:CRT_INITIALIZE_BSS=0

Looking at the ti83 for this, we're now left with some interrupt handling code which I don't know much about.

@empathicqubit
Copy link
Contributor

I honestly don't know much about the interrupt code either. I assume that it's still there even in a fully assembly project.

@zx70
Copy link
Member

zx70 commented Jan 22, 2023

I began looking at the TI84 (WabbitEmu, etc..)
Is TI-OS the vanilla ROM environment or a shell?

@empathicqubit
Copy link
Contributor

empathicqubit commented Jan 22, 2023

TI-OS is the vanilla ROM environment. However, it does not work with any of the shells either without the same modification.

To start in TI-OS, you need to open the catalog (2nd key+0), then look for Asm(. After that, go to PGRM and choose the program. Should then say

Asm(pgrmNAME

Then press ENTER

I would also test with MirageOS, since it can launch Ion apps as well: https://www.ticalc.org/archives/files/fileinfo/139/13949.html

You could try with Doors, but it's honestly trying too hard to be a desktop shell and has this clumsy mouse cursor based interface that doesn't work very well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants