Значок ресурса

Clocking On

Нет прав на скачивание
Автор: Carol Brooksbank
Год: 1985
Издатели: ZX Computing
Языки: 🇬🇧 Английский
Формат: 📼 TZX лента
Требования: 🖥️ ZX Spectrum 16K, 🖥️ ZX Spectrum 48K

Ссылки:
Страница на ZXArt
Страница на World Of Spectrum
Страница на Spectrum Computing

Скриншоты:
ClockingOn.gif


Clocking On





Carol Brooksbank keeps track of time


with this useful machine code program.





When you are planning a game program with an 'against the


clock' element, it would e useful to be able to display a


clock running continuously on the screen. The spectrum has


its own built in clock. The problem is how to display it,


and keep it running, on a machine which is not equipped for


multi-tasking.


The Spectrum handbook has a BASIC program which, by


PEEKing the three FRAMES system variables, and calculating


the time elapsed from the values held there, produces an


accurate clock. The trouble is that while the Spectrum is


doing that it is not doing anything else. It seems that you


can have the clock or your game, but not both. But it can


be done, if you know a little about the interrupt modes.





Interrupts





In the normal state of Spectrum affairs, it stops what it


is doing 50 times per second and performs the instructions


in the ROM subroutine at 0038h - updating the FRAMES


variables and scanning the keyboard. This is Interrupt


Mode 1 (IM1). But there is another Interrupt Mode, IM2.


(Actually there are two, but this is the one which concerns


us here.)


In IM2, you can direct the Spectrum, at an interrupt, to


your own subroutine in the RAM, and give it other tasks to


perform. It is a powerful instruction, but must be handled


with great care, as there are a number of conditions which


must be met if you want to avoid everything going horribly


wrong.


First, your interrupt subroutine must be short. There


are 50 interrupts per second, so if your instructions take


longer than 1/50 sec. to perform, the program will crash.


The Spectrum will not return from the interrupt subroutine


before it is called again, and it will do nothing but


repeat the first part of the subroutine over and over.


Although the Spectrum can perform around 3000 instructions


in 1/50 sec., it is easy to overrun the time. You will


still need to scan the keyboard, and the scanning routine


itself is quite a long one. When planning this program I


tried to use a machine code version of the handbook BASIC


program, using the calculator stack for the calculations,


and the ordinary RST10 printing routine for displaying the


clock. It crashed. Each calculator stack instruction calls


up various ROM subroutines, and the total number of


instructions was far too large for the time available. So


be careful of ROM subroutines. A one byte instruction on


paper can call up a very complex network of instructions in


practice.


So, I simplified the subroutine, no longer updating


FRAMES, but introducing out own clock counters, the program


variables at FF01-FF09 (7F01-7F09 for 16K). This eliminated


the calculator stack, but I was still using a series of


RST10 instructions for the display, and, I found another


snag. Using RST10 alters some of the system variables -


TV FLAG, S POSN, etc. So although the subroutine could just


be performed in the time, the main program went haywire


because of the corrupted variables. When I tried to save


all the variables involved at the beginning of the sub-


routine, and restore them at the end, we were over time


again. So out went RST10 in favour of direct POKEs into the


screen for displaying the clock.


It is essential to save all the registers at the start


of an interrupt subroutine and restore them before return-


ing from it to avoid their corruption causing the main


program to crash. Even a BASIC program will crash if you


neglect this. Although the clock routine does not appear to


end with a series of POP instructions, they are there. It


ends by jumping into the usual interrupt subroutine at the


point where it scans the keyboard, and the POPs are the


final instructions of that subroutine.


The other major difficulty is the devious route the


Spectrum takes to its interrupt subroutine when in IM2. On


an interrupt, it jumps to an address whose low byte is FFh,


and whose high byte it gets from the I register (not to be


confused with the IX or IY registers). At this vector ad-


dress, it expects to find the actual subroutine address. So


before the IM2 instruction, you must load the I register


with the high byte of the vector address, and the vector


address must hold the two bytes of the subroutine address,


in the usual format of low byte first. In this program, the


48K subroutine is at FEC5, and the vector address at FEFF,


so the I register holds FE, and at FEFF and FF00 are the


bytes 5CFE. When returning to IM1, the I register must be


restored to its usual value of 3F.


But, there is another complication. If the I register


holds any value between 40h and 7Fh, nasty things happen to


the screen display. You need someone who knows more about


what goes on under the Spectrum's bonnet than I do to ex-


plain why, but it is so. This does not matter to the 48K


user, who can use 80FF or higher, but for 16K folk it


means that there is nowhere in the RAM where you can put


the vector address. So the 16K user wishing to use IM2 must


rummage about in the ROM, looking for an address, whose low


byte is FF, at which there are two bytes which point to an


address in the 16K RAM. I came up with six. I am not pre-


pared to swear there are no more, but these are enough to


go with (see figure 1).





Figure 1. Available addresses for the 16K user





ROM ADDRESS


(vector) Bytes There RAM ADDRESS


06FF DD71 71DD


0FFF 186D 6D18


14FF 6964 6469


19FF 225D 5D22


1EFF CD67 67CD


28FF 5C7E 7E5C





Of these, some are so low in memory that they would leave


very little room for BASIC. I stopped looking when I found


the one at 28FF, which gives the RAM address 7E5C, because


the subroutine fits neatly there without overwriting the


user-defined graphics.





Conversion





To simplify the conversion between machines, I have placed


the 48K routine at FE5C. The listing is for 48K, but I have


underlined the bytes which must be changed for 16K, and


included the 16K bytes in brackets. [Naturally, the TZX


contains both versions of the code.] By a happy accident,


the subroutine ends at FEFE, so that the vector address can


follow immediately, between the subroutine and the program


variables. If the 'FF' address falls in the middle of the


subroutine, the vector address must beplaced there, with a


jump instruction immediately preceding it so that the sub-


routine operation can by-pass the subroutine address bytes.


The start and stop routines do not have to reside in


memory where I have placed them. If your main program is in


machine code, the first bytes should be the start routine,


and the final ones the stop routine. If you leave them


where they are when your program is in BASIC, RANDOMIZE


USR 65057 (32289) will start the clock and RANDOMIZE USR


65109 (32341) will return to the normal interrupt status.


If you wish to pause the clock during your program, e.g. to


allow for reading instructions without loss of time, simply


stop it with RANDOMIZE USR 65109 (32341). RANDOMIZE USR


65057 (32289) will start it again from where it left off.


To start it again from zero, yo must POKE 0 into the


following variables:





Spectrum 48K Spectrum 16K


FF02 65282 7F02 32514


FF03 65283 7F03 32515


FF05 65285 7F05 32517


FF06 65286 7F06 32518


FF08 65288 7F08 32520


FF09 65289 7F09 32521


FF01 65281 7F01 32513





Do not overwrite the clock "window" with anything during


your program or you will lose the words "TIME ELAPSED" [but


see the demo program on the TZX for a way around this]. The


clock irself will reappear, however, even after CLS. The


window is AT:





0, 24-31


1, 24-32


2, 24-31





Enter CLEAR 65056 (32288) to protect the clock above


RAMTOP. If you have just time for an hour's programming


before the pub opens or you have to feed the cat, you can


run the clock and keep an eye on the time while you work.


Once the code is loaded, RANDOMIZE USR 65057 (32289) will


start the clock, and you can use the Spectrum quite nor-


mally. NEW will delete "TIME ELAPSED", but so long as you


remembered the CLEAR 65056 (32288) instruction, the clock


will continue. SAVE, LOAD, VERIFY and using the printer


will pause it briefly, and a scroll will remove "TIME


ELAPSED" and give you a copy of the time the scroll oc-


curred above the running clock, but otherwise it will run


accurately for 99 hrs., 59 min., 59 sec., after which the


printing will be corrupted. (Anyone who wants to spend more


than four days and nights at the keyboard can write their


own routine!)


The following BASIC will allow you to insert any com-


mands you need for your own program.





10 RANDOMIZE USR 65057 (32289)


9899 GO TO 9999


9900 CLEAR 65056 (32288)


9910 LOAD ""CODE


9999 RANDOMIZE USR 65109 (32341)





Save the program on tape /before/ running the clock, so


that it always starts from zero when loaded.





SAVE "program" LINE 9900


SAVE "clock"CODE 65057 (32289),235





The clock runs in real time, but you can change this by


POKEing other values into FE69, 65129 (7E69, 32361). Values


lower than 32h, 50d, will speed the clock up, higher values


will slow it, enabling you to change the level of difficul-


ty in your program. If you wish to make some operation in


your program conditional on a certain time having passed,


you can PEEK the variables. For example, PEEKing M10, FF05,


65285 (7F05, 32517) will tell you that 10 minutes have


passed each time the value held there changes.





Sources





When devising the program, I made extensive use of the


following books:





LOGAN


Understanding your Spectrum


(Technical explanation of interrupt instructions.)


[Your humble typist seconds this recommendation.]





LOGAN & O'HARA


The complete Spectrum ROM disassembly


(Details of the purpose and structure of all ROM


subroutines.)


(Both above published by Melbourne House.)





ROSS-LANGLEY


The Spectrum machine code reference guide


(Full listing of all ROM addresses and the bytes


held there.)


(Published Interface.)








[The following note accompanied the assembly code listing


of the routine.]


** With the exception of FF04 and FF07, the locations


FF01 - FF0B are the variables which will be altered as the


program proceeds. The CODE of the digits is 30h - 39h, and


the CODE of ":" is 3Ah. As the value stored in the variable


for each digit is not the CODE, but the true value, the


value stored is (CODE-30h). To store ":" in the same con-


vention, it is therefore necessary to store 0A wherever it


is required to print ".".








[ And finally, a word about the TZX that goes with this


text. It should be apparent that I've provided loadable


CODE files for both 48k and 16k Spectrums. I've also


added the programs I used to load those into memory,


should those be useful to someone.


The TZX starts with a demonstration program, which deter-


mines whether it is running on a 16k or 48k Spectrum


(unless you fiddle with RAMTOP before loading it, in


which case, serves you right), loads the appropriate CODE


file, sets a few address variables, and proceeds to show


how to use the routine. Note how, apart from the LOADing


and address setting, it was possible to keep the code


identical for both types of Spectrum. RLB, 01/2012 ]
Автор
Verter_bot
Загрузки
0
Просмотры
2
Расширение
zip
Размер
2.1 КБ
Хэш
50b33f45ff95559c08cdbeda1736e25c
Первый выпуск
Последнее обновление

Оценки

0.00 звезд(ы) 0 оценок
Назад
Вверх