[comp.sys.cbm] ML help!!!

grx0644@uoft02.utoledo.edu (12/01/90)

I wrote an assembly program for my c128. Its a simple program that writes the
time on the screen in the upper left hand corner. To be useful, it is started
by a sys statement and returns basic when finished. It uses the cassette buffer
as its home. I want to have the C128 to execute this program as part of the
C128's normal routine so I don't have to keep sending a sys command.  is there
a way to patch something the normal operating routine that will cause the
computer to JSR to my routine and then RTS back to what ever it was doing,
without interupting any basic programs that may be executing at the same time?

I am new to assembly so if anyone know the answer, please, I beg you, in every
day terms!!!  :)

Thanks in advance

Tony.

PS. If anyone wants the basic prg that sets the clock and the ml program that
is the clock, the are uploaded to my account and I can send them out
uuencoded!!

slobasso@raven.calpoly.edu) (I don't know ;-) (12/02/90)

In article grx0644@uoft02.utoledo.edu writes:
|I wrote an assembly program for my c128. Its a simple program that writes the
|time on the screen in the upper left hand corner. To be useful, it is started
|by a sys statement and returns basic when finished. It uses the cassette buffer
|as its home. I want to have the C128 to execute this program as part of the
|C128's normal routine so I don't have to keep sending a sys command.  is there
|a way to patch something the normal operating routine that will cause the
|computer to JSR to my routine and then RTS back to what ever it was doing,
|without interupting any basic programs that may be executing at the same time?

The best way to do this is to make a ML program run while other things run
is to link it into an interrrupt. I use the IRQ RAM vector. $0314-0315
When your program is done rather than returning (rts) you just
jmp to where the Vector usually points.
here's a sample that changes the border color of the 40col screen

. 01800  78		SEI        ;these 7 lines set up the interrupt vector
. 01801  A9 0D		LDA #$0D   ;LSB of address
. 01803  8D 14 03	STA $0314
. 01806  A9 18		LDA #$18   ;MSB of address
. 01803  8D 15 03	STA $0315
. 0180B  58		CLI
. 0180C  60		RTS

; note that the program starts at the address used above

. 0180D  CE 20 D0	DEC $D020 ;this is your actual program, it finishes by
. 01810  4C 65 FA	JMP $FA65 ;jumping to FA65 (EA31 for the C64)

this program will run while a basic or ML program is running w/o
interrupting it. Try to have the program as small as possible
since it is executed very often. For instance a clock need only be updated
once every second. I think that the interrupt will get called 60 times
a second.


-- 
---                             | I took a course in speed reading and was
Steve LoBasso                   | able to read War and Peace in twenty minutes.
slobasso@polyslo.CalPoly.EDU    | It's about Russia.
ucbvax!voder!polyslo!slobasso   |                    -- Woody Allen

hh2x@vax5.cit.cornell.edu (12/02/90)

In article <1990Nov30.161424.2348@uoft02.utoledo.edu>,
grx0644@uoft02.utoledo.edu writes:
> I wrote an assembly program for my c128. Its a simple program that writes the
> time on the screen in the upper left hand corner. To be useful, it is started
> by a sys statement and returns basic when finished. It uses the cassette buff

sd05@terre.DMI.USherb.CA (Sylvain Tremblay / Eric Trepanier) (12/03/90)

In article <1990Nov30.161424.2348@uoft02.utoledo.edu> grx0644@uoft02.utoledo.edu writes:
>I wrote an assembly program for my c128. Its a simple program that writes the
>time on the screen in the upper left hand corner. To be useful, it is started
>by a sys statement and returns basic when finished.It uses the cassette buffer
>as its home. I want to have the C128 to execute this program as part of the
>C128's normal routine so I don't have to keep sending a sys command.  is there
>a way to patch something the normal operating routine that will cause the
>computer to JSR to my routine and then RTS back to what ever it was doing,
>without interupting any basic programs that may be executing at the same time?
>I am new to assembly so if anyone know the answer, please, I beg you, in every
>day terms!!!  :)
>Thanks in advance
>Tony.


What you must do is an interrupt service routine.  The 6502 processor is
interrupted every 1/60th second to perform some housekeeping chores, such
as scanning the keyboard for a key, displaying any new characters, and so on...
When the "interruption" occurs, the current processor's volatil state
(Acc, Xreg, Yreg, Processor Status, MMU cfg, ...) is saved on the stack, and
then the 8502 jumps through an indirect vector to its interrupt service
routine.  When it is done, it exits via a RTI (ReTurn from Interrupt) instead
of a RTS.  It is possible to have a custom routine executed as part of the
normal interrupt sequence by making the indirect vector point to your own
routine, instead of the Kernal's.  Once your routine is executed, you should
JMP to the remainder of the Kernal's interrupt service routine, or else
the 8502 will not scan the keyboard anymore, and the computer will appear to
be locked (crashed).  It is important to disable interruptions (with a SEI,
SEt Interrupt disable bit) while you are modifying the indirect vector.  If
you don't, an interruption might occur just after you modify the low byte, but
before you modify the high byte.  This would cause the 8502 to jump to an
invalid address, and thus, probably crash.

This is what your code should look like:


InitClk: sei                     ; disable interruptions

         lda     IIRQ            ; get interrupt vector value, low byte
         sta     JumpIRQ+1       ; and store at end of custom interrupt routine
         lda     IIRQ+1          ; get interrupt vector value, high byte
         sta     JumpIRQ+2       ; and store at end of custom interrupt routine

         lda     #<Clock         ; get low byte of custom interrupt routine
         sta     IIRQ            ; and store in interrupt vector, low byte
         lda     #>Clock         ; get high byte of custom interrupt routine
         sta     IIRQ+1          ; and store at end of custom interrupt routine

         cli                     ; reenable interruptions

         rts                     ; exit from clock initialisation routine


Clock:   ...                     ; Clock interrupt service routine

JumpIRQ: jmp     $FFFF           ; Jump to the remainder of the IRQ routine


When you want to initialize the clock, just do a SYS to InitClk.  And, provided
that your clock service routine is ok, it should run continuously, without
disturbing any basic program.  You should probably have a clock disable routine
which would restore the interrupt vector (IIRQ = $0314) back to its original
value.

One thing you must keep in mind is that you CANNOT fiddle with the VDC while
you're in your interrupt routine.  This is a more delicate subject and would
require that you know exactly how the VDC works, and I'm not sure you do.
This means that your clock can only work in 40 columns mode.  It could be
made to work in 80 columns mode too, but it would require a lot more work
on your part.  Stick with to 40 column clock first.  If you can do it, then
try doing it in 80 column.


Well I hope that this short letter gives you a hint.  Interrupts are the most
powerful and intersting aspects of machine language programming.  If you learn
to master them, you make your C128 do great things, like a mouse driver or
background jobs, or so on...

There is a book by Jim Butterfield that I highly recommend to any novice or
intermediate machine language programmers, it is called:

Machine Language For The Commodore 64, 128 And Other Commodore Computers

Its publisher's address is:

A Brady Book, Published by Prentice Hall Press, New York, New York 10023

This book is an excellent ml tutorial which covers every aspects of machine
language programming on the C128.


Eric Trepanier

-- 
+-----------------------------------------------------------------///------+
|  Sylvain Tremblay        INTERNET: sd05@terre.USherb.CA    __  ///   /|  |
|  Eric Trepanier               CIS: 71640,666               \\\///  #  |  |
|  Sherbrooke, Qc, Can          TEL: (819) 820-0976           \XX/     _|_ |

treesh@vangogh.helios.nd.edu (12/04/90)

What you need to do is use whats called an IRQ splice.  I dont know exactaly
how this is done on the C128, but I would guess its not that hard.  If its
anything like its done on the 64, you will need to make one small modification
to the end of your ML routine, insteat of having it RTS, you will have it
JMP to a locations somplace in the Kernal ROM.  You will then alter an
IRQ vector, so that it now points to your ML, and when your ML is done it
will jump to the place in ROM to where it normally would have gone if you
had not alterd the vector in the first place.

IRQ's are jumpped to 60 times a second on the 64, and are for all pracitcal
pourposes transparrent to BASIC.

ctfm

md3b+@andrew.cmu.edu (Matthew Donald Drown) (12/07/90)

I haven't done this in a couple years, I have an Amiga now, but for some help.

To set up an IRQ you must set the address you want to be jumped to, in
lo-byte, hi-byte format.  Then your code must end with a JMP $ea31. 
That should be it.  A simle prog that keeps the screen black no matter
what you do would be:

Begin:
  sei
  lda #<irqthingy
  ldx #>irqthingy
  sta $0314
  stx $0315
  cli
  rts

IrqThingy:
  lda #$00
  sta $d020
  jmp $ea31

That should do, more advanced stuff is stopping the interupt at certain
screen spots.  Not much harder, but get this part working first.
-Matt

(BTW, was anyone on QLink 2 years ago?  And if so do you remember a guy
called Nemesis?  That's me, I wrote a demo maker for people.)