Author |
Message |
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 02 Dec 2011 08:56:37 am Post subject: |
|
|
Hi. I've been reading a very known tutorial how to program in assembler for TI 83, called asm in 28 days. My problem is that i cant understand lesson 13.
For example:
IX_Offset .EQU $+2
INC (IX + 0) ; $DD $34 $00
LD A, (IX_Offset)
ADD A, 3
LD (IX_Offset), A
What does the "$+2" mean? And how does it affect IX offset?
Second example:
"It can also be used to save a register faster than the stack:"
LD (save_a), A
LD (save_hl), HL
; Do some math on A and HL ...
save_a .EQU $+1
LD A, $00
save_hl .EQU $+1
LD HL, $0000
again what does the $+1 mean?
PS. Is there any way to run asm programs without asm( on the calculator without the need to change OS? |
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 02 Dec 2011 03:53:56 pm Post subject: |
|
|
I like these questions! Okay, so I am pretty sure you understand how addresses work if you are up to lesson 13, so it should be easier to explain
When you have a label called HL_Times_A and you do call HL_Times_A+2, you will call the address 2 bytes into the routine (because of the +2). Likewise, $+2 will reference 2 bytes from that address.
So the first question:
Code:
IX_Offset .EQU $+2
INC (IX + 0) ; $DD $34 $00
the DD3400 in the comment is the opcode for INC (IX + 0) as it would appear in memory. So two bytes from the label points to the 00. So say you do this:
Code:
ld a,13
ld (IX_Offset),a
you change the memory to DD340D which is the same as INC (IX + 13).
To really be fluent with SMC will probably take time as you will need to get familiar with what the opcodes look like in memory. I was lucky because I started programming Z80 by programming directly in hexadecimal on the calculator. Needless to say, I knew all the opcodes and how to change them, so SMC was very easy for me :/
So pretty much, any time you see "$" you are referencing the address of the code at the start of the line. I hope that helps!
As for running ASM programs without the Asm( token can actually be done. There are some apps that install hooks that let you do that, but if you want to do the fun way, you can create your own hook. Interested? I can gladly give help there > |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 02 Dec 2011 06:23:34 pm Post subject: |
|
|
Thank you so much! I could go on without this, and you made it so simple!
As for the hook- this is the soution i was most hoping for , so it would be very nice to see your solution to this problem. |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 03 Dec 2011 09:00:53 am Post subject: |
|
|
I encountered another problem. It is a little difficult to me to understand what some of the instructions are doing, so im going to add a comment to every line.
LD H, 0 ;load 0 to high byte
LD L, A ;and A to low byte
LD HL, HL ;what is point of doind this?
LD DE, VectTbl ;load value of ClearScreen into DE
ADD HL, DE ; Add hl and de, no idea why
LD A, (HL) ;Is it really possible to load a 2 byte adress into a 1 byte reg?
INC HL ;increase value of(HL)+ value of ClearScreen(DE) by one. Why?
LD H, (HL) ;again, can you do this?
LD L, A ; totally lost right now
JP (HL)
VectTbl:
.DW ClearScreen
.DW PutSprite
.DW DrawLine
.DW EndPrgm
.DW BlackScreen |
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 03 Dec 2011 09:24:08 am Post subject: |
|
|
EDIT: Also, so that folks don't think there was a double post, a bot had posted between the two posts and I had to delete it. It may look like a double post, but it is not :P
Hehe, okay, I think I have this. In case you have ever programmed in TI-BASIC, I will give an analogy, too.
Think of the memory as a giant list where each byte is a list element:
(Also, the ld hl,hl is a non-existent instruction and is supposed to be add hl,hl
Code:
|Asm |BASIC |Description
+----------------+-------------+-----------
ld h,0 ;0→H |Loads 0 into H (the high byte)
ld l,a ;A→L |and A to low byte
add hl,hl ;HL+HL→HL |adds hl to itself. This is what it is supposed to be XD
ld de,VectTable ;VectTable→DE |VectTable points to an address. The address
; | of the vector table is stored to DE
add hl,de ;HL+DE→HL |The vector table contains two-byte addresses. HL=2A,
; | DE points to the table. HL+DE points to the wanted address
ld a,(hl) ;L1(HL)→A |This stores the byte pointed to by HL into A. This is the low byte of the wanted address.
inc hl ;HL+1→HL |HL points to the high byte of the address wanted
ld h,(hl) ;L1(HL)→H |H now has the high byte of the address
ld l,a ;A→L |A was the low byte, so now HL is the address of the call
jp (hl) ;Goto HL |This jumps to the address HL
VectTbl:
.DW ClearScreen
.DW PutSprite
.DW DrawLine
.DW EndPrgm
.DW BlackScreen
I hope this helps! Also, I am trying to get all of the code ready for an "Auto Asm" thing. I have the Putnam Competition soon, though, so my day is about full... I just have to comment stuff, now, and then test it :)
I pretty much copied it from Grammer, so it actually will check the header of a program and you can make it do different things based on a header (like if a BASIC program started with ::0: you could make it load). It also copies the program to RAM, so the code gets a bit complicated. Still, this means you will be able to run ASM programs from RAM or Archive without the Asm( token
Last edited by Guest on 03 Dec 2011 09:25:46 am; edited 1 time in total |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 03 Dec 2011 10:38:34 am Post subject: |
|
|
You are amazing. |
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 03 Dec 2011 09:49:03 pm Post subject: |
|
|
Okay, so I haven't had time to comment, but if you see questionable content, please ask! This code is a bit complicated and uses some undocumented routines, but what it does is:
When you press enter on the homescreen, this checks if the first byte is the "prgm" token. If it is, it then checks the contents of the program named. If the first two bytes are BB6D or BB6C, it runs the program as an assembly program. if the program is in archive, it gets copied to RAM in a temporary var called @ (so it won't delete any normal pre-existing programs).
Also, this has room for improvement as I pretty much copied and pasted this and then modified it.
For those who want to just use this, it pretty much lets you run assembly programs without the Asm( token. If you leave off the Asm( token, you can run it from Archive, too.
Code:
.nolist
#define TASM
#define bcall(xxxx) rst 28h \ .dw xxxx
#define equ .equ
HookLoc equ 86ECh
TempWord1 equ 84AFh
TempWord3 equ 84B1h
TempWord4 equ 84B3h
TempWord5 equ 84B5h
.list
.org 9D93h
StartProg:
.db $BB,$6D
ld de,HookLoc
ld hl,GrammerHook
ld bc,768
push de
ldir
in a,(6)
pop hl
bcall(5026h) ;This is the bcall "EnableParserHook" It may or may not be documented officially, so here is the info: http://wikiti.brandonw.net/index.php?title=83Plus:BCALLs:5026
ret
GrammerHook:
.db 83h
or a
jr z,$+4
ExitHook3:
xor a \ ret
push hl
ld hl,(8478h)
ld bc,2305h
or a
sbc hl,bc
pop hl
jr nz,ExitHook3
push hl
push de
push bc
push af
di
ld hl,2305h
xor a \ ld (847Ah),a
ld (8478h),hl
bcall(42F1h)
ex de,hl
ld c,(hl) \ inc hl
ld b,(hl) \ inc hl
ld de,8478h
ldir \ xor a
ld (de),a
ld a,5 \ ld (8478h),a
call IsOP1GrammerProg
jr nz,EndHook
or a \ jr z,ProgIsInRAM
push af
push de
push bc
ld hl,TempName
rst 20h ;this is the same as Mov9ToOP1
bcall(42F1h)
jr c,$+5
bcall(4FC6h)
pop hl \ push hl
ld a,22
bcall(4E70h) ;Creates a new var
pop bc
pop hl
pop af
inc de \ inc de
call ReadArc
ld hl,TempName
rst 20h
ProgIsInRAM:
pop af
pop bc
pop de
pop hl
bcall(4E7Ch)
or 1 \ ret
EndHook:
; ld hl,8485h ;location of header
; ION=BB6DC918
; MOS=BB6DC901
; DCS7=BB6DAAC9
pop af
pop bc
pop de
pop hl
xor a \ ret
OP1NameLength equ HookLoc+$-GrammerHook
;Returns the name length in HL
xor a \ ld b,a \ ld c,a
ld hl,8478h
cpir
ld h,a \ ld l,a
scf \ sbc hl,bc
ret
IsOP1GrammerProg equ HookLoc+$-GrammerHook
;Outputs:
; A is the flash page the data is on
; BC is the size of the program
; DE points to the program data
; HL points to the data (header data)
; z is set if it is a grammer var
; nz if it isn't
call OP1NameLength
push hl
bcall(42F1h)
ld a,b \ pop bc
ex de,hl
or a \ jr nz,GetArchSize
ld c,(hl) \ inc hl
ld b,(hl) \ inc hl \ push bc
ld de,8485h \ push de \ ld bc,4
ldir \ pop hl \ pop bc
jr CheckHeader
GetArchSize:
; push af
; in a,(6) \ ld (TempWord1+1),a
; pop af
add hl,bc
ld c,9
add hl,bc
; out (6),a
bit 7,h
jr z,$+7
res 7,h \ set 6,h
inc a
; call nz,IncHLMem1+4
ld de,8478h+11
ld bc,11
push hl
push de
call ReadArcData
pop de \ ex de,hl
pop de \ inc de \ inc de
ld c,(hl) \ inc hl
ld b,(hl) \ inc hl
CheckHeader:
push de
push af
ld a,(hl) \ inc hl \ cp $BB \ jr nz,NotHeader
ld a,(hl) \ inc hl \ sub 6ch
jr z,$+3
dec a
NotHeader:
pop hl
ld a,h
pop hl
ex de,hl
ret nz
ld (TempWord3),a
ld (TempWord4),bc
ld (TempWord5),hl
ret
ReadArc equ HookLoc+$-GrammerHook
ReadArcData equ HookLoc+$-GrammerHook
or a
jr nz,$+5
ldir
ret
push af \ in a,(6)
ld (TempWord1),a
pop af
out (6),a
ArcReadLoop equ HookLoc+$-GrammerHook
dec hl
call IncHLmem1
ldi
jp pe,ArcReadLoop
push af
ld a,(TempWord1)
out (6),a
pop af
ret
ReadArcEnd equ HookLoc+$-GrammerHook
IncHLmem1 equ HookLoc+$-GrammerHook
; speed 1 page total
;
inc l ; 4 4*16384 65536
ret nz ;11| 5 64*5+16320*11 179840
inc h ; 4 4*64 256
ret po ;11| 5 11*63+5 698
ld h,40h ; 7 7 7
in a,(6) ; 11 11 11
inc a ; 4 4 4
out (6),a ; 11 11 11
ret ; 10 10 10
TempName equ HookLoc+$-GrammerHook
.db 22,64,0 ;22 means a temp program, the 64,0 is the zero terminated name (prgm@)
.end
(Also, yes, this code can be a lot smaller XD I just kept the handmade routines to read archive instead of using bcalls) |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 05 Dec 2011 12:19:00 pm Post subject: |
|
|
So i have some additional questions, but this time about the calculator itself, and a little bit hardware theory.
1. The calculator uses so called ROM-calls. An example is BCALL(_ClrLCDFull), am i right?
2. Can i edit ROM-calls? Does the calculator use EEPROM or just ROM?
3. When i want to get mashine code of my program i run it on simulator(TI 83 Plus Flash Debugger), then search for adress 9D95h
on a disassembly window and check the code. What am i looking at? Is it RAM? Its a little strange, because there are holes in
the adresses.
4. Where is TI-OS? Can its edit the code?
PS. Thanks for the solution. I will try to understand when im done with the tutorial because if i'd ask about something i dont udnerstand i'd ask about every single line .
Last edited by Guest on 05 Dec 2011 12:22:18 pm; edited 1 time in total |
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 05 Dec 2011 01:38:32 pm Post subject: |
|
|
I do not have any formal training so the meaning of terms often escapes me, but here is what I can tell you:
1) The flash pages can be written to-- if you know the secret protocol (not really secret, but it is advanced)
2) Certain pages of flash and are protected so writing does nothing (and I believe some pages cannot be read, either).
3) Certain RAM pages are also protected that prevent executing code
4) I believe the flash chip is a NAND chip or something like that. Whatever it is called, what it means is that you can change a set bit to reset, but not vice-versa. So 1→0, but not 0→1.
5) As for editing ROM calls, if you have the power of editing the flash, you technically could edit these. I personally think creating an OS is easier, though.
6) If you want the machine code, you can look at the address 9D95h. Assembly programs are executed from RAM (which is what allows for self modifying code).
7) Adresses are stored little endian (all words, in fact) on the calc. So pretty much, call 9D95h looks like CD959D in RAM.
Also, if you can figure out how to get a ROM image of your calc (the process is a bit complicated), I would suggest WabbitEmu for debugging. Plus, if you use WabbitEmu, you can edit flash as well from the debugger.
If at any point you want a breakdown of what happens at bcall(), I do happen to know a little. I have class soonish, though, so it might not be an immediate response.
Finally, my answers gave me an idea for one of my programs. It involves making Apps use less power... (reading from flash uses more power than reading from RAM and the TI-84+ has an extra RAM page that is largely unused) |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 06 Dec 2011 04:39:26 pm Post subject: |
|
|
Thank you for your answers. As allways very helpful.
Here come another questions that i have :)
Is there any easy way to avoid memory leak when pressing [2nd][ON] When GetKey is running?
I heard of call called _GetKeyRetOff which will return kOff when [2nd][ON] is pressed, but
i have to press [2nd][Mode](quit) to be able to turn off my calculator.
1.Is there any way of getting the calc to return to its normal key-input state so that i dont have to press enything else
to turn it off when program ends?
2.How do i harmlessly turn off calculator? With asm of course.
3.Is it possible to output an integer with _DispHL that is smaller than 256 and not get 2 spaces from left corner?
4.How to connect 2 decimal numbers to make a new number? For example i have 2 in HL and 5 in A, what do i do to make it
25? Im aware that i can multiply HL with 10 and then add A, but is there any other way?
Last edited by Guest on 06 Dec 2011 05:16:14 pm; edited 1 time in total |
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 06 Dec 2011 10:41:21 pm Post subject: |
|
|
To turn off the calc with [2nd][ON]:
Code:
bcall(_GetKeyRetOff) ;The equate here is 500Bh
cp 3Fh ;THis is the key code for kOff
jr nz,NotOff
ld a,1
out (3),a ;Sending 1 to port 3 turns the calc off
ret
NotOff:
; <<continue code>>
I don't get what you mean by question 1...
I think the code above answers question 2 (just send 1 to port 3)
A code for DispHL that doesn't have the spaces takes a bit of code, but here is one way:
Code:
DispHLNoSpace:
ld de,10 ;sets e=10, d=0
call HL_Div_E
push af
inc d
ld a,h \ or l
jr nz,DispHLNoSpace
ld b,d
Disping:
pop af \ or 30h
bcall(_PutC)
djnz $-6 ;djnz Disping
ret
HL_Div_E:
;Inputs:
; HL is the numerator
; E is the denominator
;Outputs:
; A is the remainder
; B is 0
; C is not changed
; DE is not changed
; HL is the quotient
;
ld b,16
xor a
add hl,hl
rla
cp e
jr c,$+4
inc l
sub e
djnz $-7
ret
I have not actually tested this code, by the way, but I believe it will work.
As for combining two, one digit numbers, here is a way to combine a number in l and a:
Code:
ld h,a
add a,a
add a,a
add a,h
add a,a ;At this point, a is multiplied by 10
add a,l ;L is added to A
So if you wanted to combine 2 and 5 to get 25, you would use the above code with 2 in A and 5 in L. 25 is then stored to A.
If you want to do the method you had with HL and A, you just do:
Code:
ld d,h \ ld e,l
add hl,hl
add hl,hl
add hl,de
add hl,hl
add a,l ;L is added to A
ld l,a
Now HL contains the two digit number (as does A and L). Does this help? |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 07 Dec 2011 01:48:38 am Post subject: |
|
|
What i ment is that when you use _GetKeyRetOff and quit the program you cant turn off your calculator
because "all subsequent _GetKey's will behave similarly". This means that i cant turn it off till i press [2nd][Quit] after
i quit the program. I think this is really annoying if users have to know that they have to do that after they execute my programs.
Thank you again |
|
Back to top |
|
|
NanoWar
Newbie
Joined: 21 Sep 2008 Posts: 30
|
Posted: 07 Dec 2011 04:18:55 am Post subject: |
|
|
I never use _GetKey because of that interrupting behavior. Use _GetCSC (4018h) in a loop instead (as used here).
Code: waitClear:
bcall(_GetCSC)
cp skClear
jr nz, waitClear
ret
These key codes (like "skClear") can be found here or here. |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 07 Dec 2011 11:18:28 am Post subject: |
|
|
NanoWar wrote:
I never use _GetKey because of that interrupting behavior. Use _GetCSC (4018h) in a loop instead (as used here).
Code: waitClear:
bcall(_GetCSC)
cp skClear
jr nz, waitClear
ret
These key codes (like "skClear") can be found here or here.
Yes but with this solution you dont have access to 2nd and alpha keys and you have to do everything manually. I only use it for [2nd][Quit] and i guess it isnt so much work.
I've made a little test program here but i cant understand where i made a mistake. If you find it- please dont give me solution but only an information where it is
I really WANT to learn asm, even though it goes terrible so far.
Code: bcall(_RunIndicOff)
bcall(_ClrLCDFull)
Begin:
LD HL, 0
LD (CurRow), HL
Loop:
PUSH HL
bcall(_GetKey)
POP HL
CP kQuit
RET Z
CP k0
JR C, Loop
CP k9
JR NC, Loop
PUSH AF
SUB 8Eh ;key constant. k5 - 8Eh = 5
LD D, H
LD E, L
ADD HL, HL
ADD HL, HL
ADD HL, DE
ADD HL, HL ;thanks for optimalization
LD D, 0
LD E, A
ADD HL, DE
POP AF
CP kEnter
CALL Z, Disp
JR Loop
Disp:
bcall(_DispHL) ;after disp hl must be reset so im not saving my registers
LD HL, (Begin)
POP DE ;get return adress
PUSH HL ;replace it with new
RET
This compiles right so if you see any misspell ignore it
Last edited by Guest on 07 Dec 2011 11:21:00 am; edited 1 time in total |
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 07 Dec 2011 05:55:00 pm Post subject: |
|
|
Well i have a solution to your _GetKey issue that you wouldn't otherwise learn. Before exiting, run this code:
Code:
res 7,(iy+28h)
That will allow you to turn off the calc when you are back on the home screen. I had to take a look at the bcall data itself, so you probably wouldn't find the documentation on that too easily.
Now, looking at your code, the first thing I see that might be an issue is at the end:
Code:
LD HL, (Begin)
What you want to do is LD HL, Begin. the () means it will read the two bytes at the address Begin instead of loading the address of Begin into HL.
I will say that there are a few optimisations to make, but it looks like you are just trying to do some pretty code hacky things, so have fun! |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 08 Dec 2011 09:21:35 am Post subject: |
|
|
Hmm, well when you run an assembly program on the calculator, the code is copied to the address 9D95h. So even if the program itself isn't at 9D95h, the code is run from there. However, if you are making your own shell that loads the program to another address or just runs it where it is, that could pose a problem . In that case, you will want to find some way to use relative addresses. (so using jr instead of jp and not using call). |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 09 Dec 2011 05:04:34 pm Post subject: |
|
|
Thank you again. I hope it doesnt bother you that i ask so many questions. |
|
Back to top |
|
|
Xeda112358
Active Member
Joined: 19 May 2009 Posts: 520
|
Posted: 09 Dec 2011 05:39:59 pm Post subject: |
|
|
No, it does not bother me at all I like being able to help out and it gives me something to do! Plus, it means a bit more activity here >.> |
|
Back to top |
|
|
jammasterz
Advanced Newbie
Joined: 28 Nov 2011 Posts: 72
|
Posted: 11 Dec 2011 06:24:54 am Post subject: |
|
|
Im very happy to hear that . Im not shure if i will be able to continue learning asm untill christmass, because i have 5 tests comming. Thank you for your help! |
|
Back to top |
|
|
|