LC-3, LDI isn't getting right address? - lc3

My code below is supposed to simply print a prompt, but it's printing a bunch of y-looking characters instead. Any idea of what I'm doing wrong?
CODE:
startPrompt .STRINGZ "Enter 'E' to encrpyt, 'D' to decrpyt, X to quit\n"
startPromptAddress .FILL startPrompt
LDI R0, startPromptAddress
PUTS

I think you want LEA, not LDI.
LEA Loads a register with the ADDRESS of LABEL (not its contents!). Often used with .STRINGZ and PUTS to print a string.
LDI gets the address that is stored at the LABEL (or an offset), and then gets the VALUE at THAT address (this is the indirect "i" part of LDI).
Here's the full code that should work in a typical LC3 simulator (I used the one at lc3tutor.org to verify:
--------------- cut here ---------------
.ORIG x3000
startPrompt .STRINGZ "Enter 'E' to encrpyt, 'D' to decrpyt, X to quit\n"
LEA R0, startPrompt; load the address at 'startPrompt' into R0
PUTS; print characters starting at R0 and continuing until the null character is reached (automatically part of the memory initialized when you use the .STRINGZ directive).
.END
-------------- cut here ---------------
Hope this helps
Jeff

Related

Get Assembly without Labels

I am currently attempting to output assembly using the script below:
for instr in currentProgram.getListing().getInstructions(True):
print("\" " + str(instr) + "\\n\\t" + "\"")
It produces output like below:
" ADD RBX,0x1\n\t"
" CMP RBP,RBX\n\t"
" JNZ 0x001012b0\n\t"
" ADD RSP,0x8\n\t"
This works great for every instruction except anything that modifies the execution flow, such as jumps or calls. I'd ideally like the output to be:
" ADD RBX,0x1\n\t"
" CMP RBP,RBX\n\t"
" JNZ -0x10\n\t"
" ADD RSP,0x8\n\t"
Because in this example, the JNZ instruction jumps to an address a distance of 0x10 before this instruction. I can see this in the instruction bytes of 75 ea (75 being a jnz, and ea being -0x10), but I don't know how to get this value from the ghidra scripting api. Can you help me get this value for the output I'm expecting?

Executing TI BASIC from a String

Is it possible to Execute TI BASIC from a string? Such that:
execute(":Disp Str1")
would Print out Str1?
It could be done with a small Asm( program that takes a string (from Ans), turns it into a BASIC program, and executes it. For example:
.nolist
#include "ti83plus.inc"
.list
.org userMem-2
.db $BB,$6D
ld hl,SavesScreen
ld (hl),tTheta
inc hl
ld (hl),0
inc hl
push hl
bcall(_AnsName)
rst rFindSym
ex de,hl
ld c,(hl)
inc hl
ld b,(hl)
dec hl
inc bc
inc bc
pop de
ldir
ld hl,SavesScreen
ld a,6
bcall(_ExecuteNewPrgm)
; no ret because _ExecuteNewPrgm does not return
This is not ideal,
No safety in case Ans did not contain a string (could be added).
A program named θ should not exist, because it will be overwritten. If prgmθ already exists and is archived, then it does not work at all. (could be improved)
prgmθ is not deleted afterwards. (not sure how to do this)
When prgmθ is done, it quits to the Homescreen, it does not return to the calling program. (not sure how to do this)
Aside from that, it does work, for example:
:"TESTING->Str1
:":Disp Str1
:Asm(prgmRUNSTR
Looks like this afterwards:
You can create the assembly program by typing this into a normal program:
AsmPrgmBB6D21
EC86365B2336
0023E5EF524B
D7EB4E23462B
0303D1EDB021
EC863E06EF3C
4C
It can be made smaller with AsmComp(.
Unfortunately, no, not like this- expr and eval only work on expressions.

Local Label Address in GNU GCC Assembely

I'm trying to use some PPC assembly code in C, but I'm having trouble understanding and transposing this particular piece of ASM into the GNU GCC format:
...
b 1f
1:
lis p0, HI(2f)
ori p0, p0, LO(2f)
mtsrr0 p0
rfi
2:
mtssr0 p1 /* Restore srr0 & srr1 */
mtssr1 p2
...
The lines in question are those that reference 2f. I'm aware of Local Labels and I can only assume that is what is meant by 2f in those two instructions. Looking at the more general mtspr instruction, the RS parameter should be a register.
EDIT: Peter Cordes helped me understand the intent of this code. It looks like we're using lis and ori to build the 32 bit address of the label 2: to load into ssr0. The following quote from the PowerPC Architecture Primer completely explains the intent of this assembly.
Save/restore registers (SRR0 and SRR1) — SRR0 holds the address of the instruction where an interrupted process should resume. When rfi executes, instruction execution continues at the address in SRR0. In Book E, SRR0 is used for non-critical interrupts.— SRR1 holds machine state information. When an interrupt is taken, MSR contents are placed in SRR1. When rfi executes, SRR1 contents are placed into MSR. In Book E, SRR1 is used for non-critical interrupts.
Now that I understand what the code is doing, I need to represent this code with GNU GCC in C:
__asm__ __volatile__ (
"b 1f\n\t"
"1:\n\t"
"lis %2, %hi(2f)\n\t"
"ori %2, %2, %lo(2f)\n\t"
"mtsrr0 %2\n\t"
"rfi\n\t"
"2:\n\t"
"mtsrr0 %0\n\t" /* srr0 = p1 */
"mtsrr1 %1\n\t" /* srr1 = p2 */
: "=r" (p1), "=r" (p2)
: "r" (val), "r" (p1), "r" (p2));
This yields the following error (twice, for each instance of 2f I assume:
invalid 'asm': operand number missing after %-letter
Commenting out the lines with instructions lis and ori allows the code to compile without errors.

EBNF: prefix and suffix-like operator in assembly code production

I'm trying to write down 6809 assembly in EBNF to write a tree-sitter parser.
I'm stuck on one certain production. In 6809 assembly, you can use a register as an operand and additionally de- or increment it:
LDA 0,X+ ; loads A from X then bumps X by 1
LDD ,Y++ ; loads D from Y then bumps Y by 2
LDA 0,-U ; decrements U by 1 then loads A from address in U
LDU ,--S ; decrements S by 2 then loads U from address in S
Mind the "missing" first operand in the second line of code. Here are the productions I wrote:
instruction = opcode, [operand], ["," , register_exp];
...
register_exp = [{operator}], register | register, [{operator}];
register = "X" | "Y" | "U" | etc. ;
operator = "+" | "-";
The problem is register_exp = .... I feel like there could be a more elegant way to define this production. Also, what happens if only a register is given to register_exp?
You probably need
register_exp = [{operator}], register | register, [{operator}] | register;
to allow register names without operators. Why do you find it not so elegant? Quite descriptive.

Why am I getting extra characters?

Program Description
I used .BLKW to allocate 20 locations for each character that the user inputs and for now, I just want to display the string the user typed at the first prompt. (This will be a pig latin translator, hence the second prompt; but right now I just want to see if I can print out the user input)
The Problem
The problem is that when I run it, I get extra characters at the end.
For example:
English Word: apple
Pig-Latin Word: apple
English Word: at
Pig-Latin Word: atple
English Word: set
Pig-Latin Word: setle
My Program
.ORIG x3000
START ST R1,SAVER1
ST R2,SAVER2
ST R3,SAVER3
LD R5,ENTER
REPEAT LEA R0,PROMPT ; loading the starting address of prompt
PUTS ; displays PROMPT on screen
LEA R4,ENGLWORD ; sets aside memory locations for typed characters
INPUT GETC ; now that user has typed, read char into R0
ADD R6,R5,R0 ; adds the negative value of the ASCII enter key code to the input character
BRz PIGPROMPT ; if the sum of the ASCII codes from step before is 0, that means user pressed enter so go to PIGPROMPT
OUT ; write char in R0 to console
STR R0,R4,#0 ; store typed character into memory location
ADD R4,R4,#1 ; increment memory location so you write next character to the next location
BRnzp INPUT ; break no matter what to the INPUT step to receive next typed character
PIGPROMPT LEA R0,PIG ; loads starting address of pig latin prompt
PUTS ; displays pig latin prompt on screen
LEA R0,ENGLWORD
PUTS
BRnzp REPEAT
LD R1,SAVER1 ; restore R1 to original value
LD R2,SAVER2 ; restore R2 to original value
LD R3,SAVER3 ; restore R3 to original value
HALT
SAVER1 .BLKW 1 ; allocates 1 memory location for SAVER1
SAVER2 .BLKW 1 ; allocates 1 memory location for SAVER2
SAVER3 .BLKW 1 ; allocates 1 memory location for SAVER3
ENGLWORD .BLKW #20
ENTER .FILL xFFF6 ; the negative value of the ASCII code for the enter key
NEWLINE .FILL x000A
PROMPT .STRINGZ "\nEnglish Word: " ; initializes a sequence of stringLength+1 memory locations to hold string
PIG .STRINGZ "\nPig-Latin Word: "
DSR .FILL xFE04
DDR .FILL xFE06
KBSR .FILL xFE00
KBDR .FILL xFE02
.END
Attempted Solution
I was thinking that the problem was that R4 holds the string of the first user input throughout the whole program. So for a solution, I thought about clearing R4 after it is displayed so that it's ready to take the next user input. Does anyone know how I would do that?
The key here is how PUTS works -- it prints all the characters starting at the address in R0 until it reaches a 0 ('\0' not '0').
The first time you run it, the memory will contain ['A','P','P','L','E'], followed by zeroes if you didn't randomize memory contents when you loaded the program. This means that a PUTS call will return "APPLE". When you enter the new word, it doesn't clear out that memory, so entering "at" will result in ['A','T','P','L','E'], and your print routine will print "ATPLE".
In order to properly finish the word, you need to add a '\0' (a.k.a. 0) to the element after the last character to print. In other words, if your memory contains ['A','T','\0','L','E'], your print routine will print "AT".
Aqua's right, the PUTs command is looking for a zero to stop printing characters to the screen. I've added two lines of code just after PIGPROMPT and it seems to be working as intended.
Revised:
.ORIG x3000
START ST R1,SAVER1
ST R2,SAVER2
ST R3,SAVER3
LD R5,ENTER
REPEAT LEA R0,PROMPT ; loading the starting address of prompt
PUTS ; displays PROMPT on screen
LEA R4,ENGLWORD ; sets aside memory locations for typed characters
INPUT GETC ; now that user has typed, read char into R0
ADD R6,R5,R0 ; adds the negative value of the ASCII enter keycode to the input character
BRz PIGPROMPT ; if the sum of the ASCII codes from step before is 0, that means user pressed enter so go to PIGPROMPT
OUT ; write char in R0 to console
STR R0,R4,#0 ; store typed character into memory location
ADD R4,R4,#1 ; increment memory location so you write next character to the next location
BRnzp INPUT ; break no matter what to the INPUT step to receive next typed character
PIGPROMPT AND R0, R0, #0 ; clear R0
STR R0,R4,#0 ; store typed character into memory location
LEA R0,PIG ; loads starting address of pig latin prompt
PUTS ; displays pig latin prompt on screen
LEA R0,ENGLWORD
PUTS
BRnzp REPEAT
LD R1,SAVER1 ; restore R1 to original value
LD R2,SAVER2 ; restore R2 to original value
LD R3,SAVER3 ; restore R3 to original value
HALT
SAVER1 .BLKW 1 ; allocates 1 memory location for SAVER1
SAVER2 .BLKW 1 ; allocates 1 memory location for SAVER2
SAVER3 .BLKW 1 ; allocates 1 memory location for SAVER3
ENGLWORD .BLKW #20
ENTER .FILL xFFF6 ; the negative value of the ASCII code for the enter key
NEWLINE .FILL x000A
PROMPT .STRINGZ "\nEnglish Word: " ; initializes a sequence of stringLength+1 memory locations to hold string
PIG .STRINGZ "\nPig-Latin Word: "
DSR .FILL xFE04
DDR .FILL xFE06
KBSR .FILL xFE00
KBDR .FILL xFE02
.END
All I did was store a '0' value at the end of the user's string, that way when PUTs is called it will stop at the zero value.

Resources