I know this probably isn't the best place to put this, but I was wondering why some asm programs give an Invalid error.
|
We're glad you came by, but you might find what you're looking for elsewhere. TI-Basic Developer is not the site it once was. While its information on commands and other calculator features remains almost second-to-none, its forum, archives, and even hosting service, Wikidot, have been decaying for years. The calculator community would love to see what you're working on, or help you in your next coding adventure, but TI-Basic Developer is no longer the place to do it. Instead, you should head over to Cemetech (primarily American) or TI-Planet (primarily international). Both are active, well-established forums with their own archives, chatrooms, reference material, and abundant coding tools and resources. We'll see you there, we hope. |
what are you doing when this happens?
An assembly program might give such an error for any number of reasons; not least, because it was coded to throw that error (I doubt that's the case, though).
If it's an uncompiled hex code, it might give that error because one of the characters in the code is wrong (only numbers 0-9 and letters A-F are allowed, plus the AsmPrgm token or any number of newlines). If it's not, my only guess is that the header (which ought to be $BB $6D, the "compiled assembly program" token) is wrong. Once the program actually starts running, the only reason errors might happen is if the program does it on purpose - a crashed assembly program will be more serious trouble than an ERR:INVALID.
One other possibility is that you are trying to run an assembly program directly from the program menu, which only works if you have noshell installed.
I'm fairly sure that gives ERR:SYNTAX instead.
How do you use the "compiled asm token." I thought all you had to do was:
.nolist
#include "ti83plus.inc"
.list
.org $9D95
(code here)
.end
And after that, just compile it.
You've been reading a guide to TI-83 programming. For TI-83+ assembly programs, you have to do this (the .nolist and .list are optional):
.nolist
#include "ti83plus.inc"
.list
.ord $9D93
.db $BB, $6D
;code here
.endthe $BB, $6D is the compiled AsmPrgm token (you can find it in the token tables on this site, under Miscellaneous Tokens).
Edit: you might also write the header like this (which uses constants defined in ti83plus.inc):
.nolist
#include "ti83plus.inc"
.list
.org userMem-2
.db t2ByteTok, tasmComp
;code here
.endThank you, it works now.
Hey, If you know this much about asm, can you make me an asm program that takes the entire graph screen and turns it into Str1 somewhat like:
asm(prgmSTOREPIC ;store the screen
clrdraw ;clears the screen
"154vgfjksgjroijgksfg"->Str1 ;Stores the string
asm(prgmCALLPIC ;uses stored string to recall pic
I have a better idea. Since you seem to be learning assembly, how about you write the program yourself? It's a very simple program, and should be a good exercise. In fact, it's almost as simple as copying the data from PlotSScreen directly to where Str1 is stored, and back. (Almost, because there's a few bytes you can't have in a string - $00, $04 (→), $2A ("), and the two-byte tokens to be on the safe side).
If you need help, ask questions.
So far:
.nolist
#define rstMov9To0P1 20h
#define rstFindSym 10h
#include "ti83plus.inc"
.list
.org 9D95h
.db $BB, $6D
LD HL,str1
rst rstMov9To0P1
rst rstFindSym
JR C,Okay
B_call(DelVarArc)
Okay:
SET FullScrnDraw,(IY+ApiFlg4)
SET GrfSplitOverride,(IY+SGrFlags)
ld BC,768
ld hl,plotsscreen
ldir
ret
str1:
.db StrngObj,tVarStrng,tStr1,0
.end
.endAny ideas, corrections?
One problem that I see right off the bat is that you're loading data to a string that doesn't exist. This isn't TI-Basic, which will take care of little details for you. Here, you need to create the string first:
ld hl, 768
bcall(_CreateStrng)On the other hand, you don't need to set the flags you're setting. They only affect the way graphscreen bcalls work, and you're dealing with the graph buffer directly.
Once you've taken care of these little details, you can take care of sanitizing the string.
.nolist
#define rstMov9To0P1 20h
#define _DelVarArc 4FC6h
#define rstFindSym 10h
#include "ti83plus.inc"
.list
.org 9D95h
.db $BB, $6D
LD HL,str1
rst rstMov9To0P1
rst rstFindSym
JR C,Okay
B_call(_DelVarArc) ;Won't compile right (produces error)
Okay:
ld hl, 768
b_call(_CreateStrng)
ld BC,768
ld hl,plotsscreen
ldir
ret
str1:
.db StrngObj,tVarStrng,tStr1,0
.end
.endWhen I compile it, it says that the b_call doesn't exist.
b_call is case-sensitive, so don't capitalize it.
Also, FYI, _DelVarArc, rMOV9TOOP1, and rFINDSYM are already defined in ti83plus.inc, you don't need to do it again.
I compiled it, it gave no errors. When I ran it, it did nothing.
.nolist
#include "ti83plus.inc"
#define rstMov9To0P1 20h
#define rstFindSym 10h
.list
.org 9D95h
.db $BB, $6D
LD HL,str1
rst rstMov9To0P1
rst rstFindSym
JR C,Okay
JR failed
b_call(_DelVarArc)
Okay:
ld hl, 768
b_call(_CreateStrng)
ld BC,768
ld hl,plotsscreen
ldir
failed:
ret
str1:
.db StrngObj,tVarStrng,tStr1,0
.end
.endIt just does nothing when I run it. It just displays "DONE." Any suggestions.
Also can you explain why i load 768 into hl and then call the CreateStrng b_call. why 768?
You want the string to be 768 bytes long, so that all of plotsscreen will fit into it.
And one of the problems I see (though I missed it before) is the .org $9d95 — as I said earlier, it should be $9d93 to accommodate for the header. Putting in the wrong .org will mean your labels (Okay, failed, and str1) will be off by 2 bytes.
When I ran the program, Str1 was finally created.
It was:
""
There was nothing in it.
Interestingly enough, I think I might have figured part of it out.
When I went into my memory window, it said str1 was 11 bytes, not 768. That makes me think that:
ld hl, 768isn't how you store the strings size.
This will work:
.nolist
#include "ti83plus.inc"
#define rstMov9To0P1 20h
#define rstFindSym 10h
.list
.org 9D93h
.db $BB, $6D
LD HL,str1
rst rstMov9To0P1
rst rstFindSym
JR C,Okay
JR failed
b_call(_DelVarArc)
Okay:
ld hl, 768
b_call(_CreateStrng)
ld BC,768
ld hl,plotsscreen
inc de
inc de
ldir
failed:
ret
str1:
.db StrngObj,tVarStrng,tStr1,0,0
.end
.endThe two changes I made - first, inc de twice because the string's data starts with two size bytes (and overwriting them will obviously wreak havoc on the string's size). Second, I added a second 0 to the str1 name - not sure why exactly, but it seemed to help.
I made a change to the code. I also now need to know how to "weed out" the sto and double-quote characters.
.nolist
#include "ti83plus.inc"
#define rstMov9To0P1 20h
#define rstFindSym 10h
.list
.org 9D93h
.db $BB, $6D
LD HL,str1
rst rstMov9To0P1
rst rstFindSym
JR C,Okay
b_call(_DelVarArc)
JR failed
Okay:
ld hl, 768
b_call(_CreateStrng)
ld BC,768
ld hl,plotsscreen
inc de
inc de
ldir
failed:
ret
str1:
.db StrngObj,tVarStrng,tStr1,0,0
.end
.endWell, that's the tricky part. The idea is you replace the "ldir" instruction by a loop, in which you check the byte at (hl), and usually write the same byte to (de) - except when it's 0, store, quote, or a two-byte token, for which you have to create some other system.
The one problem is that some bytes of the graph screen will end up being more than one byte of the string, so you don't know exactly how large the string will be (anywhere from 768 to 1536 bytes). You'll want to get some "scratch space" - a temporary location to write the encoded data to, then create the string once you know how big it should be.
I don't exactly know what you mean by that, but could you please do it. I mean, couldn't we just have it work like:
| binary | hex output |
|---|---|
| 0000 | 0 |
| 0001 | 1 |
| 0010 | 2 |
| 0011 | 3 |
| 0100 | 4 |
| 0101 | 5 |
| 0110 | 6 |
| 0111 | 7 |
| 1000 | 8 |
| 1001 | 9 |
| 1010 | A |
| 1011 | B |
| 1100 | C |
| 1101 | D |
| 1110 | E |
| 1111 | F |
I know that this will make the size of the string 1536 bytes, but the goal of this program was to make a recallable string. Size doesn't matter.
OK, here's a loop that converts bytes to hex (replace ldir with this):
Loop:
ld a, (hl)
rra \ rra \ rra \ rra
call ConvertNibble
ld a, (hl)
call ConvertNibble
inc hl
dec bc
ld a, b
or c
jr nz, LoopAnd the ConvertNibble code is right here:
ConvertNibble:
and %1111
add a, $30
cp $3A
jr c, NotAThroughF
add a, 7
NotAThroughF:
ld (de), a
inc de
retP.S. don't forget to make the string size be 1536 instead of 768 now.
P.P.S. This could be optimized using RLD but I don't want to confuse you.
At which point? Compiling it, or running it? It works fine for me…
Sounds like you're running out of space in the string and writing into the memory right after it. That shouldn't happen… see if your code is different from what I have anywhere.
.nolist
#include "ti83plus.inc"
#define bcall rst 28h \ .dw
.list
.org userMem-2
.db t2ByteTok, tasmComp
ld hl, Str1Name
rst rMOV9TOOP1
rst rFINDSYM
jr c,Okay
bcall _DelVarArc
Okay:
ld hl, 1536
bcall _CreateStrng ;create the string with 1536 bytes (768*2)
ld bc, 768 ; bc is the loop counter (we'll loop 768 times,
ld hl, PlotSScreen ; over every byte of PlotSScreen)
inc de
inc de ; skip the first two bytes of the string (size bytes)
Loop:
ld a, (hl) ; get the byte from plotsscreen
rra \ rra \ rra \ rra ; shift bytes 4-7 to bytes 0-3.
call ConvertNibble ; convert bytes 0-3 to character 0-F.
ld a, (hl) ; get the byte again, this time, no shifting
call ConvertNibble ; convert bytes 0-3 to character 0-F.
inc hl ; move to next byte
dec bc ; decrease loop counter
ld a, b
or c ;check if bc is 0
jr nz, Loop ; if it's not, keep looping.
ret
ConvertNibble:
and %1111 ; mask to only keep the low nibble
add a, $30 ; numbers 0-9 are characters $30-$39
cp $3A ; check if we're in that range
jr c, NotAThroughF ; if we are, good, we're done.
add a, 7 ; otherwise, add 7 because chars A-F are $41-$46
NotAThroughF:
ld (de), a ; now write this char to the string
inc de ; and move to the next byte.
ret
Str1Name:
.db StrngObj, tVarStrng, tStr1, 0, 0
.end
.endthis code works:
.nolist
#include "ti83plus.inc"
#define rstMov9To0P1 20h
#define rstFindSym 10h
.list
.org $9D93
.db $BB, $6D
ld hl, Str1Name
rst rstMov9To0P1
rst rstFindSym
jr c,Okay
jr failed
b_call(_DelVarArc)
Okay:
ld hl, 1536
b_call(_CreateStrng)
ld bc, 768
ld hl, PlotSScreen
inc de
inc de
Loop:
ld a, (hl)
rra \ rra \ rra \ rra
call ConvertNibble
ld a, (hl)
call ConvertNibble
inc hl
dec bc
ld a, b
or c
jr nz, Loop
ret
ConvertNibble:
and %1111
add a, $30
cp $3A
jr c, NotAThroughF
add a, 7
NotAThroughF:
ld (de), a
inc de
ret
failed:
ret
Str1Name:
.db StrngObj,tVarStrng,tStr1,0,0
.end
.endSo, now, how do I change it back ??? Please tell me how to change it back. Also, since I am trying to figure out asm like I did basic, (Without a tutorial), can you comment your code. (If it's not too much to ask.)
Commented.
For changing it back, you want to find the string in much the same way you did it earlier, except we want the string to exist, rather than the opposite (so switch jr c, Okay to jr c, Failed, and remove the bcall _DelVarArc). After that:
ex de, hl ; now, hl points to start of string
inc hl ; again, move past sign bytes
inc hl
ld de, PlotSScreen
ld bc, 768 ; loop 768 times
Loop:
push bc ; back up counter
call ConvertNibbleBack ; char A-F in string to bits 0-3 of a
add a, a
add a, a
add a, a
add a, a ; shift bits 0-3 to bits 4-7 by doubling
ld b, a ; move this to b to back it up
call ConvertNibbleBack ; char A-F in string to bits 0-3 of a
add a, b ; get bits 4-7 back to get whole byte
ld (de), a
inc de ; copy a to PlotSScreen and move to next byte
pop bc ; restore counter
dec bc ; decrement counter
ld a, b
or c
jr nz, Loop ; loop again if counter isn't 0
bcall(_GrBufCpy) ; copy PlotSScreen to the screen
retAnd the code for ConvertNibbleBack:
ConvertNibbleBack:
ld a, (hl) ; get the character
inc hl
sub $30 ; convert chars '0'-'9' to numbers 0-9.
cp 10 ; check if the result is in that range
ret c ; if it is, we're done.
sub 7 ; convert chars 'A'-'F' further to numbers 10-15.
retCode should work, but I haven't tried it, tell me if it doesn't.
Doesn't work:
.nolist
#include "ti83plus.inc"
#define rstMov9To0P1 20h
#define rstFindSym 10h
.list
.org $9D93
.db $BB, $6D
ld hl, Str1Name
rst rstMov9To0P1
rst rstFindSym
jr c,failed
ex de, hl
inc hl
inc hl
ld de, PlotSScreen
ld bc, 768
Loop:
push bc
call ConvertNibbleBack
add a, a
add a, a
add a, a
add a, a
ld b, a
call ConvertNibbleBack
add a, b
ld (de), a
inc de
pop bc
dec bc
ld a, b
or c
jr nz, Loop
b_call(_GrBufCpy)
ret
ConvertNibbleBack:
ld a, (hl)
sub $30
cp 10
ret c
sub 7
ret
failed:
ret
Str1Name:
.db StrngObj,tVarStrng,tStr1,0,0
.end
.endYour ConvertNibble routine is missing an 'inc hl' I added in there slightly after the original post. As a result, the routine was copying the first character of the saved string to every byte of the screen.
Yes, it does. The instruction " ld (de), a" is key to that. To use other logic when writing to the screen, you could do something like this instead (replace xor (hl) with anything else you like):
ex de, hl
xor (hl)
ld (hl), a
ex de, hl