Jump to content
IGNORED

Lowercase with KSCAN


lucien2

Recommended Posts

I'm trying to make some low level library for GCC.

 

When the TI starts up, the SCAN routine (>000E) reads only uppercase. Then when I load Editor/Assembler, it reads lowercase too.

 

What do I need to do to have lowercase with KSCAN without loading E/A? Some CRU stuff with Alphalock?

 

Here's KSCAN and GPLLNK for GCC (sorry, no comments). The only problem is this lowercase thing.

 

 

Assembly part

gplws	equ	0x83E0
gr4	equ	gplws+8
gr6	equ	gplws+12
stkpnt	equ	0x8373
ldgadd	equ	0x60
xtab27	equ	0x200E
getstk	equ	0x166C


def	memcpy
memcpy	
L1	movb	*r2+,*r1+
dec	r3
jne	L1
b	*r11


def	kscan
kscan	lwpi	gplws
bl	@>E
lwpi	>8300
b	*r11


def	gpllnk
glnkws	equ	0x2000
gpllnk	data	glnkws,glink1
rtnad	data	xmlrtn
gxmlad	data	0x176C,0x50
glink1	li	r0,gpllnk
li	r2,>200e
li	r3,5
gplln0	mov	*r0+,*r2+
dec	r3	
jne	gplln0
mov	*r11,@gr4
mov	@2(R13),@gr6
mov	@xtab27,r12
mov	r9,@xtab27
lwpi	gplws
bl	*r4
mov	@gxmlad,@0x8302(r4)
inct	@stkpnt
b	@ldgadd
xmlrtn	mov	@getstk,r4
bl	*r4
lwpi	glnkws
mov	r12,@xtab27
rtwp

C part

#define VDP_READ_DATA_REG   (*(volatile char*)0x8800)
#define VDP_WRITE_DATA_REG  (*(volatile char*)0x8C00)
#define VDP_ADDRESS_REG     (*(volatile char*)0x8C02)
#define VDP_READ_FLAG       0x00
#define VDP_WRITE_FLAG      0x40
#define VDP_REG_FLAG        0x80
#define SEED                (*(int*)0x83C0)
#define STATUS              (*(char*)0x837C)
#define KEY_UNIT            (*(char*)0x8374)
#define KEY                 (*(char*)0x8375)
#define JOYST_X             (*(char*)0x8376)
#define JOYST_Y             (*(char*)0x8377)
#define FAC                 (*(volatile int*)0x834A)

void vdp_copy_from_sys(int index, char* src, int size) {
char* end = src + size;
VDP_ADDRESS_REG = index;
VDP_ADDRESS_REG = (char)(index >>  | VDP_WRITE_FLAG;
while(src < end) VDP_WRITE_DATA_REG = *src++;
}

void vdp_write_reg(int i,char c) {
VDP_ADDRESS_REG=c;
VDP_ADDRESS_REG=i|VDP_REG_FLAG;
}

void interrupts() {
asm("limi 2");
asm("limi 0");
}

char random_byte(char c) {
SEED=SEED*0x6FE5+0x7AB9;
int i=((unsigned)SEED>>+(SEED<<;
return (unsigned)i%c;
}

char vdp_read_byte(int index) {
VDP_ADDRESS_REG = index;
VDP_ADDRESS_REG = (char)(index >>  | VDP_READ_FLAG;
asm("nop");
return VDP_READ_DATA_REG;
}

int key_scan(char* key) {
KEY_UNIT=0;
asm("bl @kscan");
*key=KEY;
char c=STATUS&0x20;
return c;
}

void gpl_link(int addr) {
asm(
	"mov %0,r1\n\t"
	"blwp @gpllnk"
	:
	:"r"(addr)
	:"r1"
);
}

void main() {
int i=0;
char c;
FAC=0x900;
gpl_link(0x18);
FAC=0xB00;
gpl_link(0x4A);
while(1) {
	interrupts();
	if(key_scan(&c)) {
		vdp_copy_from_sys(i,&c,1);
		/* c=random_byte(5); */
		i++; if(i>=32*24)i=0;
		gpl_link(0x34);
	}
}
}

 

 

Link to comment
Share on other sites

The keyboard type is set by writing to the byte >8374.

 

TurboForth writes the value >05 into >8374 to enable a 'full' keyboard scan in both upper and lower case.

 

More info here: http://nouspikel.group.shef.ac.uk//ti99/tutor1.htm#KSCAN

 

Thanks, it works!

 

int key_scan(char* key) {
KEY_UNIT=5;
asm("bl @kscan");
*key=KEY;
char c=STATUS&0x20;
return c;
}

Link to comment
Share on other sites

Can you do this instead ? If not, why not ? If yes, will it be that bit smaller in size and more speedy ? I guess I could try it out, but I haven't followed the GCC stuff. Sorry.

 

return STATUS&0x20;

:)

 

That's what I did at first:

#define STATUS              (*(char*)0x837C)

int key_scan(char* key) {
KEY_UNIT=5;
asm("bl @kscan");
*key=KEY;
return STATUS&0x20;
}

def	key_scan
key_scan
li   r2, >500
movb r2, @-31884
* Begin inline assembler code
* 47 "main.c" 1
bl @kscan
* End of inline assembler code
movb @-31883, *r1
movb @-31876, r1
andi r1, >20
b    *r11

 

With a "char" local variable:

#define STATUS              (*(char*)0x837C)

int key_scan(char* key) {
KEY_UNIT=5;
asm("bl @kscan");
*key=KEY;
char c=STATUS&0x20;
return c;
}

def	key_scan
key_scan
li   r2, >500
movb r2, @-31884
* Begin inline assembler code
* 47 "main.c" 1
bl @kscan
* End of inline assembler code
movb @-31883, *r1
movb @-31876, r1
andi r1, >2000
sra  r1, 8
b    *r11

 

I'm not expert enough in C to say that it's wrong.

Link to comment
Share on other sites

No, the first block is wrong, since it's masking the low byte of the word but put the data in the high byte. It's perfectly legal C syntax to do return STATUS&0x20, GCC seems to have gotten confused about the data size. It knew it was a char when it did the MOVB, but then treated it as an integer for the masking. What's missing is it didn't expand from char to int inbetween (or, in fact, before returning, so the return value would be multiplied by 256). It looks like a type conversion bug.

 

I wonder what the code would be if it had been return STATUS&(char)0x20; ? I guess either way though, it missed the conversion from char to int.

 

That's not a show stopper, and it's thrilling to see how much works, but it is a gotcha. :)

Link to comment
Share on other sites

Well, that's funky.

 

A few things you should know:

 

By using inline assembly, to call "kscan" you are preventing GCC from knowing that it has to retain the "key" pointer stored in R1 and return pointer in R11. If "kscan" were to use these registers, the values stored there would be destroyed, and the C code would behave weirdly.

 

That can be fixed by doing something like this:

extern void kscan();

int key_scan(char* key) {
       KEY_UNIT=5;
       kscan();
       *key=KEY;
       char c=STATUS&0x20;
       return c;
}

 

That results in this assembly:

def	key_scan
key_scan
ai   r10, >FFFC
mov  r11, *r10
mov  r9, @2(r10)
mov  r1, r9
li   r1, >500
movb r1, @-31884
bl   @kscan
movb @-31883, *r9
movb @-31876, r1
andi r1, >2000
sra  r1, 8
mov  *r10+, r11
mov  *r10+, r9
b    *r11

ref	kscan

 

The different results you are seeing in the return values are due to GCC removing a sign extension on the read value of the STATUS macro. During the register allocation step, GCC is trying to be helpful and removing what it thinks is an unnecessary operation, since it believes that byte quantities are already stored in the least significant byte of the register.

 

I missed this when I was fixing things for the weird byte format. By using the temporary variable, you are forcing the change in data types. I need to go take a hard look at the compiler and find a fix for this. (The decimal addresses are also annoying and unhelpful. That increment in "mov *r10+, r9" should probably be removed too. Looks like I'll be busy for a while.)

 

By the way, I think TI chose to store bytes this way to allow the comparison logic to work for word and byte values. This would also remove the need for sign extend and zero extend logic. It also opens up the possibility of storing data in the otherwise unused low byte. I don't have anything to back up this reasoning, but it seems to make sense. In any event, no matter why this decision was made, we're stuck with it now.

Edited by insomnia
Link to comment
Share on other sites

I missed this when I was fixing things for the weird byte format.

 

Weird format? WEIRD FORMAT? It might be in your world, mate, but it's perfectly normal for us! :D ;)

 

By the way, I think TI chose to store bytes this way to allow the comparison logic to work for word and byte values. This would also remove the need for sign extend and zero extend logic. It also opens up the possibility of storing data in the otherwise unused low byte. I don't have anything to back up this reasoning, but it seems to make sense. In any event, no matter why this decision was made, we're stuck with it now.

 

Well, big endian is actually very common. The TMS9900 may have been one of the first/the first bits of silicon to be big endian, but IIRC all the mini's of the day were big endian. The entire 68K range is big endian etc... Don't forget the TMS9900 was an attempt to consolidate an entire CPU board into a single chip, so the big-endian constraint was already established. Anyway, sorry to hijack... I'm getting away from the GCC compiler... I'll shut up now! :D

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...