mlake@irscscm.UUCP (Marshall Lake) (09/24/90)
I have a programming problem and I'm hoping someone here can help me. I am attempting to play back a sample via timer A while allowing other things to go on as it plays. When the program attempts to start the actual playback it blows, sometimes displaying 4 bombs and sometimes 6. I have also tried to place the interrupt code into the main flow of the program to see what would happen. The bombs don't occur but nothing is emitted by the sound chip either. What am I doing wrong? The code follows: #include <osbind.h> #include <xbios.h> long *buff_cnt, *buff_end, *sound_chip = 0xff8800, *gi_write = 0xff8802; char *trumpet_sound; int snd_value, snd_out[1025] = { <table of values same as in other programs that play back samples> }; do_snd () { if (buff_cnt > buff_end) return; snd_value = (*buff_cnt + 128) * 8;*/ *sound_chip = snd_out[snd_value]; *sound_chip = snd_out[snd_value + 4]; buff_cnt++; } play (addr) char *addr; { buff_cnt = addr; buff_end = addr + 58965L; } set_snd_chip () { *sound_chip = 0; *gi_write = 0; *sound_chip = 1; *gi_write = 0; *sound_chip = 2; *gi_write = 0; *sound_chip = 3; *gi_write = 0; *sound_chip = 4; *gi_write = 0; *sound_chip = 5; *gi_write = 0; *sound_chip = 7; *gi_write = 255; *sound_chip = 8; *gi_write = 0; *sound_chip = 9; *gi_write = 0; *sound_chip = 10; *gi_write = 0; } main () { char *save_ssp; int counter, read_handle; if ((trumpet_sound = (char *) Malloc (58 * 1024L)) == 0) { printf ("\n\n NOT ENOUGH MEMORY \n\n"); exit (); } if ((read_handle = Fopen ("trumpet.spl", 0)) < 0) { printf ("\n Cannot find trumpet.spl \n"); exit (); } Fread (read_handle, 58965L, trumpet_sound); Fclose (read_handle); buff_cnt = 1L; buff_end = 0L; Supexec (&set_snd_chip); save_ssp = Super (0L); Xbtimer (0, 7, 0, &do_snd); play (trumpet_sound); counter = 0; while (1) { if (counter == 30000) break; printf ("counter = %d\n", counter++); } Xbtimer (0, 0, 0, &do_snd); Super (save_ssp); } -- Marshall Lake mlake@irscscm.UUCP ...!uunet!media!ka3ovk!irscscm!mlake
leo@ehviea.ine.philips.nl (Leo de Wit) (09/26/90)
In article <1990Sep24.122920.15704@irscscm.UUCP> mlake@irscscm.UUCP (Marshall Lake) writes: | |I have a programming problem and I'm hoping someone here can help me. | |I am attempting to play back a sample via timer A while allowing other |things to go on as it plays. When the program attempts to start the |actual playback it blows, sometimes displaying 4 bombs and sometimes |6. I have also tried to place the interrupt code into the main flow |of the program to see what would happen. The bombs don't occur but |nothing is emitted by the sound chip either. What am I doing wrong? [...] |do_snd () { | if (buff_cnt > buff_end) | return; | | snd_value = (*buff_cnt + 128) * 8;*/ | *sound_chip = snd_out[snd_value]; | *sound_chip = snd_out[snd_value + 4]; | | buff_cnt++; |} [...] |main () { [...] | Xbtimer (0, 7, 0, &do_snd); [...] |} Your do_snd routine must be coded as an interrupt routine; that is, it must end in a rte instruction; not only that, it must also mark (clear?) a bit in the I/O range (sorry, have to look this up), otherwise the system will think the interrupt is still pending (actually, I think the peripheral chip is thinking this 8-). For an example, take a peek into the ROMs to see how the system timer (timer C) is coded (the I/O address I mentioned is different, but you'll get the picture). Alternatively, you can do it the easy way, forget about programming it yourself and use the Xbios function Dosound() (but I assume there is a special reason you cannot use this?). And if you experience spurious interrupts using Xbtimer(), I got a solution for this too (8-). Cheers, Leo. P.S. The 4 bombs (illegal instruction) confirm that a wild jump was taken; this is because your code pops a return address off the stack where there is a status word and a return address.
leo@ehviea.ine.philips.nl (Leo de Wit) (09/27/90)
In article <891@ehviea.ine.philips.nl> leo@ehviea.UUCP (Leo de Wit) writes: |Your do_snd routine must be coded as an interrupt routine; that is, it |must end in a rte instruction; not only that, it must also mark |(clear?) a bit in the I/O range (sorry, have to look this up), The sequence for timer A is (I looked it up): my_timint ... do your stuff here ... bclr #5,$fffa0f rte The documentation I have says that in order to clear a bit in a MFP register, you have to write 1's into the other bits; this is in contradiction with the above (which is analogous to the ROM code). The bclr instruction to memory does both read and write a byte (correct me if I'm wrong), but this does not guarantee that 1's are written to the other bits (they must have been there already). The explanation for this instruction was something like: the 68K notifies the MFP that interrupts may be delivered; I wonder what happens if one is being delivered before the rte (this is theoretically possible, and my spurious interrupt problem seems to indicate practically too). Leo.
dac@ukc.ac.uk (David Clear) (09/28/90)
In article <892@ehviea.ine.philips.nl> leo@ehviea.UUCP (Leo de Wit) writes: > >The sequence for timer A is (I looked it up): > >my_timint > ... do your stuff here ... > bclr #5,$fffa0f > rte > This sequence is correct - I have had no problems using it. I've never seen any documents to suggest that 1s have to be written into the other bits of the "interrupt in service" register. As I understand it, when the MFP gets an interrupt, it will not signal the 68000 unless it is of a higher priority than those already in service. Similarly, if it does signal the 68000, the 68000 will not service it unless the IPL has been moved back below 6 (?). So, for general purpose, multi-level interrupts, the order of events should be: int: move.w #$2300,sr /* Also enables VBI, #$2400, disables VBI */ .. your own thang bclr.b #n,MFP_ISR[AB] rte On the subject of sampled sound drivers, as I understand it, to plug a value in a volume register you first do a register select and then you plug the data in. This can be done with a movep.w, right? Wanting to speed up his sample player, a friend of mine discovered that the sound chip only decoded the lowest bit of the address - so the CONTROL/DATA register pair were replicated throughout the address space of the chip. This means that rather than doing three movep.w instructions, you can get away with a movep.l and a movep.w. Of course, this can't be guaranteed to work. Dave. -- % cc life.c | David Clear dac@ukc.ac.uk +44 227 764000x7592 % a.out | Local Area Networks, Computing Laboratory, Segmentation fault (core dumped) | University of Kent, Canterbury, England. >>> Kernel R0M. His Mission: To rid the world of wobbly ZX-81 16K RAM packs. <<<
leo@ehviea.ine.philips.nl (Leo de Wit) (09/30/90)
In article <5558@harrier.ukc.ac.uk> dac@ukc.ac.uk (David Clear) writes: |In article <892@ehviea.ine.philips.nl> leo@ehviea.UUCP (Leo de Wit) writes: |> |>The sequence for timer A is (I looked it up): |> |>my_timint |> ... do your stuff here ... |> bclr #5,$fffa0f |> rte |> | |This sequence is correct - I have had no problems using it. I've never |seen any documents to suggest that 1s have to be written into the other |bits of the "interrupt in service" register. I'll quote my source (the Atari Profi buch, Dutch translation): - Nadat de lopende interrupt werd afgehandeld, dient de CPU het bijbehorende bit in het ISRA of ISRB "0" te maken. Een bit wordt "0" door in alle bits van het register, behalve het bedoelde bit, een "1" te schrijven. Doordat bits in het Interrupt Pending Register softwarematig alleen "0" en niet "1" gemaakt kunnen worden, wordt de inhoud van het register door het schrijven van de "enen" niet gewijzigd. (Original text to help understand a bit what it is like to read texts that are not written in your native language). | As I understand it, when |the MFP gets an interrupt, it will not signal the 68000 unless it is |of a higher priority than those already in service. The MFP can't even GET an interrupt that is of equal or lower priority than that currently being serviced, let alone notify the 68000 (by interrupting it); however such an interrupt remains pending and will be serviced when the current one terminates (if this is within the maximum amount of time it may be pending, the so-called interrupt latency). | Similarly, if it |does signal the 68000, the 68000 will not service it unless the IPL has |been moved back below 6 (?). The same holds here; the interrupt will be serviced when the IPL has been moved back below 6 (and if it is still pending then). | |So, for general purpose, multi-level interrupts, the order of events |should be: | |int: move.w #$2300,sr /* Also enables VBI, #$2400, disables VBI */ Sorry, no. The whole purpose of having multi-level interrupts is that an higher level interrupt won't be interrupted by a lower level one; this just defeats it. Also never plainly put a value in sr, OR it in or AND it out. Sorry to be such a nit-picker, Dave. Feel free to counter-attack 8-). Leo.