Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
This is an archived, read-only copy of the United-TI subforum , including posts and topic from May 2003 to April 2012. If you would like to discuss any of the topics in this forum, you can visit Cemetech's z80 & ez80 Assembly subforum. Some of these topics may also be directly-linked to active Cemetech topics. If you are a Cemetech member with a linked United-TI account, you can link United-TI topics here with your current Cemetech topics.

This forum is locked: you cannot post, reply to, or edit topics. Z80 & 68k Assembly => z80 & ez80 Assembly
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
Sven.Thomas0


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 Smile
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 >Very Happy
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 Smile, 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
Sven.Thomas0


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 Smile


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
Sven.Thomas0


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. Smile 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 Razz.


Last edited by Guest on 05 Dec 2011 12:22:18 pm; edited 1 time in total
Back to top
Sven.Thomas0


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
Sven.Thomas0


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 Smile
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 Smile
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 Razz


Last edited by Guest on 07 Dec 2011 11:21:00 am; edited 1 time in total
Back to top
Sven.Thomas0


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

Posted: 08 Dec 2011 05:48:10 am    Post subject:

Okay so i made a few changes(the paranthesis bug was actually a type mistake Razz) and the program works right.
Untill i overflow HL by typing a number that has more than 5 digits. What happens is when i press [2nd][Quit] the calc crashes.
So my first question is if overflow of HL in some way affects the top value of the stack?
EDIT: Solved- i forgot to pop 2 values from the stack Very Happy. I dont even know why i pushed those...

Another strange thing that happens is that the program is not allways loaded into 9D95h. And if i want to write the program in HEX directly on the calc i get a problem.

For example:

Code:
CALL Z, Disp  ;CCC59D

In mashine code the adress of the call i constant. What if program doesnt load at 9D95h? Then the call goes to some random empty location.


Last edited by Guest on 08 Dec 2011 06:22:20 am; edited 1 time in total
Back to top
Sven.Thomas0


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
Sven.Thomas0


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 Smile 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 Smile. 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
Display posts from previous:   
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
    » Goto page 1, 2, 3, 4  Next
» View previous topic :: View next topic  
Page 1 of 4 » All times are GMT - 5 Hours

 

Advertisement