English Amiga Board


Go Back   English Amiga Board > Coders > Coders. General > Coders. Tutorials

 
 
Thread Tools
Old 30 November 2018, 19:36   #41
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
Thanks. It is now not actual. However it sounds like another Moto's oddity for me. I needed to save C flag because every MOVE (it is yet another oddity) clears it! I could find a way to write my code without this saving. I don't know any other processor which works so unusually with arithmetic flags. x86 has PUSHF/POPF, LAHF/SAHF. They can be quite useful although rather rarely.
I have another actual problem. I need to get a key from a keyboard. I don't need to wait key if it is not pressed. So I need to check whether a key action happened and if it happened then to get the scan code. What is the easiest way to get such a functionality?
EDIT. I am going to use WaitForChar, Input and Read. However I am not sure that it is the best way. It is better for me to use an interrupt handler with direct access to ports.

Last edited by litwr; 30 November 2018 at 20:23.
litwr is offline  
Old 30 November 2018, 21:10   #42
Don_Adan
Registered User
 
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 51
Posts: 1,156
Quote:
Originally Posted by litwr View Post
Thanks. It is now not actual. However it sounds like another Moto's oddity for me. I needed to save C flag because every MOVE (it is yet another oddity) clears it! I could find a way to write my code without this saving. I don't know any other processor which works so unusually with arithmetic flags. x86 has PUSHF/POPF, LAHF/SAHF. They can be quite useful although rather rarely.
I have another actual problem. I need to get a key from a keyboard. I don't need to wait key if it is not pressed. So I need to check whether a key action happened and if it happened then to get the scan code. What is the easiest way to get such a functionality?
EDIT. I am going to use WaitForChar, Input and Read. However I am not sure that it is the best way. It is better for me to use an interrupt handler with direct access to ports.
This is easy. Use subx.l D0,D0. If you want to save Carry flag. You will be have 0 or -1 in D0.
Don_Adan is offline  
Old 30 November 2018, 21:21   #43
meynaf
son of 68k
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 46
Posts: 3,603
Quote:
Originally Posted by litwr View Post
Thanks. It is now not actual. However it sounds like another Moto's oddity for me. I needed to save C flag because every MOVE (it is yet another oddity) clears it! I could find a way to write my code without this saving. I don't know any other processor which works so unusually with arithmetic flags. x86 has PUSHF/POPF, LAHF/SAHF. They can be quite useful although rather rarely.
Call this a failed theory if you want, but the carry on the 68k has been made so that the flag for testing isn't the same as for multi-precision.
Therefore any data move will change C (usually cleared, exactly like a cmp with zero would have done). But not X. Maybe you can use X in your code rather than C ? Why do you want to preserve the carry anyway ?
meynaf is offline  
Old 30 November 2018, 21:23   #44
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
Quote:
Originally Posted by Don_Adan View Post
This is easy. Use subx.l D0,D0. If you want to save Carry flag. You will be have 0 or -1 in D0.
Thank you very much.

I have just found out that WaitForChar is buggy. It doesn't allow to set a delay to zero, with a delay equals 1 us it becomes slow and crashes after repeated calls. Please help to find another way. Is there any link to instructions about how to use kbd at the lower level?

EDIT. @meynaf Thanks to you too but I have another problem. We can discuss the oddity with flags in other thread. Indeed, I am aware of X and C flag and even wrote about them several times as a minor non-significant oddity.
litwr is offline  
Old 30 November 2018, 21:54   #45
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
I have just found an interesting thread - http://eab.abime.net/showthread.php?t=62322 - I will try to work with it. IMHO It is also unusual that Amiga misses a so ordinal function.
litwr is offline  
Old 01 December 2018, 11:18   #46
meynaf
son of 68k
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 46
Posts: 3,603
Quote:
Originally Posted by litwr View Post
I have just found out that WaitForChar is buggy. It doesn't allow to set a delay to zero, with a delay equals 1 us it becomes slow and crashes after repeated calls. Please help to find another way. Is there any link to instructions about how to use kbd at the lower level?
You can either :
- use input.device,
- kill the OS and peek keyboard directly.

But i am not sure if accessing the kbd at a low level is a good idea.


Quote:
Originally Posted by litwr View Post
IMHO It is also unusual that Amiga misses a so ordinal function.
It's not missing, it's just to be accessed in some indirect way
In a multitasking environment keyboard input has to come from some specific location : a window you opened yourself, or eventually a console window.
And grabbing keyboard input that is targeted to another application isn't exactly a polite thing to do.
The normal way of doing is using a window and ICDMP messages and this is now always what I do.
meynaf is offline  
Old 01 December 2018, 12:16   #47
kamelito
Zone Friend
kamelito's Avatar
 
Join Date: May 2006
Location: France
Posts: 1,012
how about lowlevel.library (didn't checked)
kamelito is offline  
Old 01 December 2018, 13:04   #48
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
Quote:
Originally Posted by meynaf View Post
The normal way of doing is using a window and ICDMP messages and this is now always what I do.
Thank you. But what is about games? I would like to have a full screen program not a window, something like https://www.reaktor.com/blog/crash-c...y-programming/

There should be a kind of system routine that gets scan-codes and put them into system buffer where the applications can get them from. It looks like there is no such routine.

I have tried to check ports but it work very poorly. I used the next code.

Code:
     btst #3,$dff01d
     beq .nkbdevent
     btst #3,$BFED01
     beq .nkbdevent

    ;it gets there very seldom, I have to press a key many times to get there
.nkbdevent:
What is wrong with my code? Please, I need help again.
litwr is offline  
Old 01 December 2018, 13:43   #49
meynaf
son of 68k
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 46
Posts: 3,603
Quote:
Originally Posted by litwr View Post
Thank you. But what is about games? I would like to have a full screen program not a window, something like https://www.reaktor.com/blog/crash-c...y-programming/
A full screen program still needs a window, exactly like a directx windows program in full screen mode, or even a sdl program.
You need to first setup the screen (I use OpenScreenTagList for that), then setup the window (I use OpenWindowTagList). The window needs to be backdrop/borderless.


Quote:
Originally Posted by litwr View Post
There should be a kind of system routine that gets scan-codes and put them into system buffer where the applications can get them from. It looks like there is no such routine.
That's what IDCMP messages are for.
But, hey, there can not be a global queue for key presses : imagine what would happen if several programs attempt to read them !


Quote:
Originally Posted by litwr View Post
I have tried to check ports but it work very poorly. I used the next code.

Code:
     btst #3,$dff01d
     beq .nkbdevent
     btst #3,$BFED01
     beq .nkbdevent

    ;it gets there very seldom, I have to press a key many times to get there
.nkbdevent:
What is wrong with my code? Please, I need help again.
The Amiga keyboard (unlike the one on Atari, btw) needs some handshake and has timing issues (you have to send it some pulse that has to be long enough).

When i had to do this i used something like that :
Code:
 btst #3,$bfed01
 beq .nkbdevent
 move.b $bfec01,d0
 ori.b #$40,$bfee01
.loop2
 cmpi.b #$70,$dff007
 bcc.s .loop2
 moveq #1,d2
.loop1
 move.b $dff006,d1
.loop0
 cmp.b $dff006,d1
 beq.s .loop0
 dbf d2,.loop1
 andi.b #$bf,$bfee01
 not.b d0
 ror.b #1,d0
; here you have d0.b=keycode, b7 indicates key pressed/released
But, of course, you'll have trouble if you run the above under OS.
meynaf is offline  
Old 01 December 2018, 14:14   #50
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
Thank you very much! But, yes, I have trouble. It just doesn't work. Because my program (like mentioned at reaktor.com) uses Forbid call. I can't understand how it can prevent the port at $bfec01 from normal working. So your code doesn't work at all after the Forbid call. If I skip this call then your code works but my program crashes at exit.
IMHO it is better to intercept a keyboard interrupt. So I just need to intercept interrupts check it whether it from keyboard (BTW any help how to do this can greatly accelerate my programming) and if it is keyboard's then set a flag. I can check this flag from my code and later call to Input to get a keyboard's symbol. Is it a correct idea or there is some objections?
litwr is offline  
Old 01 December 2018, 15:17   #51
meynaf
son of 68k
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 46
Posts: 3,603
Rather than Forbid(), try Disable(). Interrupts may read the port and so your code won't get anything meaningful out of it.
meynaf is offline  
Old 01 December 2018, 15:55   #52
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
Quote:
Originally Posted by meynaf View Post
Rather than Forbid(), try Disable(). Interrupts may read the port and so your code won't get anything meaningful out of it.
If it was so then the interrupt effect can be noted when there was no Forbid call but without call to Forbid your code work. So it is a kind of a mystery. However you are right it works with Disable. Thank you very much again. But I think that the code with interrupts would be better. So I have to do some more study. Indeed, if somebody has a code to set a keyboard interrupt handler it would help.
litwr is offline  
Old 01 December 2018, 17:20   #53
phx
Natteravn

phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 1,479
Yes, I know I'm a bit late, but nobody posted a real answer to this question yet, just the workaround with BASEREG.

Quote:
Originally Posted by litwr View Post
error 3005: reloc type 10, size 16, mask 0xffffffffffffffff (symbol tab + 0x0) not supported

I used VASM -m68000 -Fhunkexe -o MYFILE MYFILE.asm.

I also tried to use VASM -m68000 --no-opt -Fhunk -m68000 -o MYFILE.o MYFILE.asm. It works, it produces an obj-file. But the linker didn't work. I used vlink -bamigahunk -s -o MYFILE MYFILE.o. I get

Error 21: MYFILE.o (CODE+0x14): Reference to undefined symbol _SDA_BASE_.
What happened here is that vasm correctly identified "(tab,A6)" as a 16-bit base-relative addressing mode and wrote the appropriate relocation type into the object file.

But a base-relative addressing mode needs a base symbol to be defined, so the linker can calculate the 16-bit offsets from it. vlink looks for either of the following two symbols for that purpose: _SDA_BASE_ (Unix, SysVR4) or _LinkerDB (AmigaOS).

The linker would even provide that symbol automatically, using the address of your small-data section + 32766 as default value. But all you have to do is to reference that symbol and initialize your base register with it. For example
Code:
        xref    _LinkerDB  ; from linker
        lea     _LinkerDB,a6
at the start of your code.

The advantage of real small-data relocations compared with BASEREG is that you are not restricted to a single source file, but you may link several object files together. Unlike absolute 32-bit relocs, all these small-data relocs will disappear in the final executable.
phx is offline  
Old 01 December 2018, 17:57   #54
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
Quote:
Originally Posted by phx View Post
Yes, I know I'm a bit late, but nobody posted a real answer to this question yet, just the workaround with BASEREG.
Thank you very much. Such things are very difficult to find and require too much time to study. I don't still understand some tricks around relocation.

I have just made my code for the kbd interrupt:

Code:
         LEVEL2IADDR = $68
         move.l LEVEL2IADDR,level2ie+2   ;save and set intr vector
         move.l #level2i,LEVEL2IADDR
        ...
         move.l level2ie+2,LEVEL2IADDR  ;restore intr vector
        ...
level2i:         ;intr handler
          btst #3,$bfed01   ;kbd intr?
          beq level2ie

          move.b #1,key_ready
level2ie:    
          jmp 0
         ...
          tst.b key_ready(a3)  ;is a key pressed?
          beq .nokey

          move.l	4,a6
          lea	dosname(a3),a1   ; points to dc.b "dos.library",0
          jsr	OldOpenLibrary(a6)
	  move.l  d0,a6
          jsr     Input(a6)          ;get stdin
          move.l  d0,d1
          move.l #kbdbuf,d2
          moveq.l #4,d3
          jsr Read(a6)
.nokey:
The testing of byte variable key_ready works perfectly but Read hangs. Could anybody help with it? Maybe it tries to read kbd data from another window?..

Last edited by litwr; 01 December 2018 at 18:20.
litwr is offline  
Old 01 December 2018, 19:47   #55
roondar
Registered User

 
Join Date: Jul 2015
Location: The Netherlands
Posts: 1,364
If you are running with the OS active, you are not allowed to set your own interrupt vectors like that. If you need interrupts while using the OS you have to add your handler to the OS interrupt chain. On the other hand, if you are running with the OS disabled then you can set interrupts however you like, but you can't reliably use OS functions.

I'd guess that changing the level 2 interrupt vector by yourself breaks part of the OS, as it also uses the level 2 interrupt (the level 2 interrupt is the PORTS interrupt, which is stated to be in use by Exec here: http://amigadev.elowar.com/read/ADCD.../node0306.html). I'm almost 100% certain that this interrupt is also in part used by AmigaDOS for reading/writing files and as such the Read() function will hang if you change the vector.

Without meaning this in a negative way, perhaps it's best to learn a bit more about the environment you are using before mucking about with interrupts etc?

AmigaOS is a fully multitasking operating system and you're simply not supposed to address the hardware directly if you wish to use it*. The idea is that you use the available libraries etc to get your desired results. If you do want to use the hardware in a more direct manner, perhaps disabling the OS fits your needs better (though this does mean file I/O becomes much more tricky or impossible unless you either use a trackloader or switch the OS in/out on demand)?

*) Note that with OwnBlitter()/DisownBlitter()/WaitBlitter() you can kinda-maybe-more-or-less get away with your own Blitter programming, but even that is not recommended.

Last edited by roondar; 01 December 2018 at 19:58.
roondar is offline  
Old 01 December 2018, 21:04   #56
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
Quote:
Originally Posted by roondar View Post
If you are running with the OS active, you are not allowed to set your own interrupt vectors like that. If you need interrupts while using the OS you have to add your handler to the OS interrupt chain. On the other hand, if you are running with the OS disabled then you can set interrupts however you like, but you can't reliably use OS functions.
Please could you get some explanations? How my interrupt handler can affect anything? It doesn't interfere with OS at all.

EDIT. As I know Read does input with echo. I need to suppress the echo. Maybe it is the cause of the problem.

Last edited by litwr; 01 December 2018 at 22:51.
litwr is offline  
Old 02 December 2018, 01:56   #57
roondar
Registered User

 
Join Date: Jul 2015
Location: The Netherlands
Posts: 1,364
Allright, I'll try.

Let's start at the beginning - you use self modifying code to write an address to jump to in your interrupt handler. That is a very, very bad idea. It can easily crash any 68020+ system. Apart from that, it's also completely unnecessary.

With this in mind, a cleaner version of the above would be:
Code:
	; Note that like your code, this is not 68020+ compatible.
	; It also probably won't work because it reads from the CIA ICR register, which can cause problems for the OS.
LEVEL2IADDR	EQU	$68
	lea.l	LEVEL2IADDR,a0
	move.l	(a0),level2_vector
	move.l	#level2i,(a0)
	...
	move.l	level2_vector,(a0)
	...

	; intr handler
level2i	btst	#3,$bfed01	; NOTE: this instruction does not work as intended (discussed below in post)
	beq	level2ie

	move.b	#1,key_ready

level2ie:
	lea	level2_vector,a2
	jmp	(a2)
	...

level2_vector	dc.l	0
More importantly, you setup your interrupt handler by changing the interrupt vector yourself and pointing back to the original vector afterwards with a jmp(). This is conform the Amiga OS guidelines (more like 'demands' in this case) about how to add interrupts and this is not the way described. There is simply put no guarantee whatsoever that the OS might not decide to change the vector later - and it won't point back to your vector if it does so. Note that I'm not saying it will do so, just that there is no guarantee it won't.

And even if it does happen to work by accident, I think it's not a good idea to ignore the OS. If you want to use the OS, use the OS for interrupts as well. It saves you mucking about with vectors and won't crash if someone decides to move the VBR to Fast RAM (and your code will crash in that case).

Your actual interrupt handler also contains a flaw - it tests a single bit in the CIA ICR register. This read action clears the CIA interrupt for all flags, not just the one you read. In other words, your interrupt handler can cause other interrupts to be cleared and thus not be handled.

Quote:
Originally Posted by Amiga Hardware Reference Manual on the CIA ICR register
When you read the DATA register, its contents are cleared (set to 0), and the IRQ line returns to a high state. Since it is cleared on a read, you must assure that your interrupt polling or interrupt service code can preserve and respond to all bits which may have been set in the DATA register at the time it was read. With proper preservation and response, it is easily possible to intermix polled and direct interrupt service methods.
However, there is a more fundamental problem - you are trying to work around the OS to get keyboard data read. The Amiga DOS function Read() is not intended for keyboard reading - it's intended for reading files. If you want to read from the keyboard using OS functions, you should look into either using input.device, or using keyboard.device.

I can't give you a working example as I don't have one ready. There is an example for keyboard.device over at http://amigadev.elowar.com/read/ADCD.../node01A0.html but it notes potential problems if input.device is also in use. AFAIK the 'OS legal way' of reading the keyboard is supposedly to use input.device.

Lastly, Read() does not cause character echo. If you see character echo in a shell/cli window that is because the OS is catching the keyboard and choosing to echo. It has nothing to do with Read().

Last edited by roondar; 02 December 2018 at 02:05.
roondar is offline  
Old 02 December 2018, 12:31   #58
phx
Natteravn

phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 1,479
Quote:
Originally Posted by roondar View Post
Code:
LEVEL2IADDR    EQU    $68
    lea.l    LEVEL2IADDR,a0
    move.l    (a0),level2_vector
    move.l    #level2i,(a0)
    ...
level2ie:
    lea    level2_vector,a2
    jmp    (a2)
Or, with a higher chance of success:
Code:
        move.l  level2_vector,a2
phx is offline  
Old 02 December 2018, 12:39   #59
ross
Per aspera ad astra

ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 49
Posts: 2,169
Quote:
Originally Posted by phx View Post
Or, with a higher chance of success:
Code:
        move.l  level2_vector,a2
Well, this is the reason why, if I do not forget, I use brackets (and also a)
Code:
       movea.l  (level2_vector),a2
So to remember to myself that I want the memory content and all previous flags are untouched.

Kudos however to roondar for trying to untangle and correct that little skein of code.

Last edited by ross; 02 December 2018 at 12:54.
ross is offline  
Old 02 December 2018, 12:47   #60
litwr
Registered User

 
Join Date: Mar 2016
Location: Ozherele
Posts: 164
@roondar Thank your very much for your very useful information. Reading of $bfed01 actually disables Read. Thus I need to preserve the content of this register and restore it after the reading. I have made the next code for my interrupt handler.
Code:
level2i:   move.l d0,-(sp)
	     move.b $bfed01,d0   ;kbd

             ori.b #$80,d0
             move.b d0,$bfed01
             move.l (sp)+,d0
level2ie:    jmp 0
It doesn't work. Please help me to restore $bfed01 contents
litwr is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Misc Amiga Assembler Source Code copse Coders. General 14 20 October 2019 03:05
The 6502 assembler code in "The Terminator" (1984) Shoonay Nostalgia & memories 2 15 May 2009 14:52
Assembler System Friendly code redblade Coders. General 3 29 July 2008 13:15
Amiga Cross Assembler to code intros! - Help! D4Ni3L3 Amiga scene 6 30 May 2008 17:53
3D code and/or internet code for Blitz Basic 2.1 EdzUp Retrogaming General Discussion 0 10 February 2002 12:40

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 02:53.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.
Page generated in 0.10015 seconds with 16 queries