English Amiga Board

English Amiga Board (https://eab.abime.net/index.php)
-   Coders. Tutorials (https://eab.abime.net/forumdisplay.php?f=73)
-   -   I am trying to make my first GFX assembler code (https://eab.abime.net/showthread.php?t=95154)

litwr 30 November 2018 18:36

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.

Don_Adan 30 November 2018 20:10

Quote:

Originally Posted by litwr (Post 1288130)
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.

meynaf 30 November 2018 20:21

Quote:

Originally Posted by litwr (Post 1288130)
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 ?

litwr 30 November 2018 20:23

Quote:

Originally Posted by Don_Adan (Post 1288137)
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 30 November 2018 20:54

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.

meynaf 01 December 2018 10:18

Quote:

Originally Posted by litwr (Post 1288142)
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 (Post 1288146)
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 :p
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.

kamelito 01 December 2018 11:16

how about lowlevel.library (didn't checked)

litwr 01 December 2018 12:04

Quote:

Originally Posted by meynaf (Post 1288212)
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. :shocked

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.

meynaf 01 December 2018 12:43

Quote:

Originally Posted by litwr (Post 1288220)
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 (Post 1288220)
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. :shocked

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 (Post 1288220)
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.

litwr 01 December 2018 13:14

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?

meynaf 01 December 2018 14:17

Rather than Forbid(), try Disable(). Interrupts may read the port and so your code won't get anything meaningful out of it.

litwr 01 December 2018 14:55

Quote:

Originally Posted by meynaf (Post 1288237)
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.

phx 01 December 2018 16:20

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 (Post 1286991)
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.

litwr 01 December 2018 16:57

Quote:

Originally Posted by phx (Post 1288247)
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?..

roondar 01 December 2018 18:47

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.

litwr 01 December 2018 20:04

Quote:

Originally Posted by roondar (Post 1288270)
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.

roondar 02 December 2018 00:56

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().

phx 02 December 2018 11:31

Quote:

Originally Posted by roondar (Post 1288323)
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
:)

ross 02 December 2018 11:39

:p
Quote:

Originally Posted by phx (Post 1288368)
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 :D (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.

litwr 02 December 2018 11:47

@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. :crying Please help me to restore $bfed01 contents


All times are GMT +2. The time now is 21:10.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.

Page generated in 0.05376 seconds with 11 queries