Keyboard Input In Assembly


Klepto

Member
Joined
Jan 27, 2006
Messages
249
Location
Scotland
Website
Visit site
I'm learning ARM assembly and mostly it's going OK, but I could use some help with reading characters from stdin. I can output to stdout using the following code. PSP and RSP are aliases for the registers I'm using as stack pointers, and OS_write=0x900004.

Code:
	STMFA RSP!, {r0-r3,LR}  @ save registers and return address
	MOV r0, #1    @ 1=stdout
	MOV r1, PSP    @ point at the char
	MOV r2, #1    @ write one char
	SWI OS_write    @ perform the call
	ADD PSP, PSP, #1  	@ drop the char
	LDMFA RSP!, {r0-r3,PC}  @ restore regs and return

Basically I need the same to read a character from stdin, but I can't find any documentation on it... Anyone know?
 
0x900004 = sys_write, so sys_read should be 0x900003 with the same parameters, but with a different fd. I've no idea what the fd will be, but something tells me it's not going to be far away from stdout.

However, I'm suprised your "save/load registers" commands work (if they actually do), as they say to me "Store Multiple Full Ascending" and "Load Multiple Full Ascending". So the load is not going to pick up what the save put there, and you'll eventually overrun your stack. You may want to use STMDB (Decrement before) and LDMIA (Increment afer) instead, which will emulate a proper stack.
 
Squidge posted on Feb 12 2006 at 01:01 AM said:
0x900004 = sys_write, so sys_read should be 0x900003 with the same parameters, but with a different fd. I've no idea what the fd will be, but something tells me it's not going to be far away from stdout.

The fd should be 0, but I'm unsure of how the SWI returns the data to me. I assume I provide it with the address of the buffer and it writes it in for me, but that doesn't seem to be happening. Does it pass anything back via registers?

Squidge posted on Feb 12 2006 at 01:01 AM said:
However at I'm suprised your "save/load registers" commands work (if they actually do), as they say to me "Store Multiple Full Ascending" and "Load Multiple Full Ascending". So the load is not going to pick up what the save put there, and you'll eventually overrun your stack. You may want to use STMDB (Decrement before) and LDMIA  (Increment afer) instead, which will emulate a proper stack.

It seems to work. As I read the quick reference (page 5, bottom left, addressing mode 4), if you use FA (full ascending stack) or FD (decending) you don't need to keep track of whether and when it increments/decrements the stack pointer. The assembler generates the correct instruction based on whether you are loading or storing. Of course I'm just learning so I may well be wrong :)

This would be very easy in c of course, but I'd really like to be able to use pure assembly.

EDIT: Fixed link

EDIT: broken source
 
Last edited by a moderator:
Klepto posted on Feb 12 2006 at 02:29 AM said:
Squidge posted on Feb 12 2006 at 01:01 AM said:
0x900004 = sys_write, so sys_read should be 0x900003 with the same parameters, but with a different fd. I've no idea what the fd will be, but something tells me it's not going to be far away from stdout.

The fd should be 0, but I'm unsure of how the SWI returns the data to me. I assume I provide it with the address of the buffer and it writes it in for me, but that doesn't seem to be happening. Does it pass anything back via registers?

Squidge posted on Feb 12 2006 at 01:01 AM said:
However at I'm suprised your "save/load registers" commands work (if they actually do), as they say to me "Store Multiple Full Ascending" and "Load Multiple Full Ascending". So the load is not going to pick up what the save put there, and you'll eventually overrun your stack. You may want to use STMDB (Decrement before) and LDMIA (Increment afer) instead, which will emulate a proper stack.

It seems to work. As I read the quick reference (page 5, bottom left, addressing mode 4), if you use FA (full ascending stack) or FD (decending) you don't need to keep track of whether and when it increments/decrements the stack pointer. The assembler generates the correct instruction based on whether you are loading or storing. Of course I'm just learning so I may well be wrong :)

That is correct. There two notation for ldm/stm postfixes and it can be confusing.

From assembler docs:

Full/Empty Decrement/Increment equivalent
STMFD STMDB
LDMFD LDMIA
STMFA STMIB
LDMFA LDMDA
STMED STMDA
LDMED LDMIB
STMEA STMIA
LDMEA LDMDB
 
Last edited by a moderator:
I fixed it, was a simple typo :angry: . The fd in the comment was correct, shame the code wasn't.

Code:
/* refills the terminal input buffer. reads a line from stdin
*/ fill_TIB:
	STMFA RSP!, {r0-r2,LR}  @ save registers and return address
	MOV r0, #0    @ 0=stdin
	LDR r1, =TIB    @ point to the TIB
	MOV r2, #TIB_end-TIB  @ we want to fill the buffer
	SWI OS_read    @ perform the call
	MOVS r0, r0    @ check for voodoo error code
	BMI	1f    	@ if found do error
	LDR r2, =TIB    @ load base of TIB
	LDR r1, =TIB_size  	@ point at TIB count
	STR r0, [r1]    @ save the character count
	LDR r0, =TIB_p    @ point at TIB pointer
	STR r2, [r0]    @ and reset it
	EORS w3, w3, w3  	@ clear error code
	LDMFA RSP!, {r0-r2,PC}  @ restore regs and return

1:	MOV w3, #E_VOODOO  @ set error code
	LDMFA RSP!, {r0-r2,PC}  @ restore regs and return
 
Back
Top