--- title: "Memory/Trace Using Interrupt Mode 2" type: "article" slug: "memory-trace-using-interrupt-mode-2" url: "http://localhost/article/memory-trace-using-interrupt-mode-2/" markdown_url: "http://localhost/article/memory-trace-using-interrupt-mode-2.md" published_at: "2020-10-27T17:10:29+00:00" modified_at: "2026-07-26T10:20:50+00:00" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "Having a Z80 processor in the Timex 2068 gives the user a powerful suite of instructions to use. One of the most useful is IM2. This instruction allows the user to divert interrupts to their own routines to do almost anything imaginable. In normal operation the processing is interrupted 60 times a second so the…" category: - name: "Time Designs Magazine" slug: "time-designs" taxonomy: "category" url: "http://localhost/category/periodicals/time-designs/" post_tag: - name: "Best of Timex/Sinclair 2068 Articles and Documents" slug: "ts2068best" taxonomy: "post_tag" url: "http://localhost/tag/ts2068best/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" - name: "Type-in program" slug: "type-in-program" taxonomy: "post_tag" url: "http://localhost/tag/type-in-program/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Floyd Chrysler" slug: "floyd-chrysler" taxonomy: "indiv" url: "http://localhost/indiv/floyd-chrysler/" publication: "Time Designs Magazine" publication_r: id: 10277 title: "Time Designs Magazine" type: "periodical" url: "http://localhost/periodical/time-designs-magazine/" authors: "Floyd Chrysler" authors_r: - name: "Floyd Chrysler" slug: "floyd-chrysler" taxonomy: "indiv" url: "http://localhost/indiv/floyd-chrysler/" volume: "3" issue: "6" issues_articles: - id: 26784 title: "Time Designs Magazine v3 n6" type: "issue" url: "http://localhost/issue/time-designs-magazine-v3-n6/" pages: "14-15" pubdate: "September/October 1987" archive_link: false volumeissue: "v3n6" --- Having a Z80 processor in the Timex 2068 gives the user a powerful suite of instructions to use. One of the most useful is IM2. This instruction allows the user to divert interrupts to their own routines to do almost anything imaginable. In normal operation the processing is interrupted 60 times a second so the CPU can update the screen and read the keyboard. The CPU then returns to the next instruction it was to have executed if an interrupt had not occured. IM2 allows us to assume control and execute some instructions before returning from the interrupt. The problem with using IM2 in the 2068 is that the Z80 assumes that an interrupting device will place one byte of data on the data bus. It then combines this byte with the I register to form an address. At this address it expects to find a second value, the routine address to which control is to be passed. In the Spectrum this works very nicely, as the data bus always contains 255 (FFh), due to the way the hardware was designed. A person wanting to use IM2 can always count on the value being placed in the I register will be concatonated with FF to form an address. With the 2068, at the time of an interrupt, the data bus will have any value from 0 to 255. This makes it impossible to predict what will be combined with the I registers. In the Sept/Oct 1985 Sinc-Linc (from the Toronto Timex-Sinclair Users Club) [Bob Mitchell](http://localhost/indiv/bob-mitchell/) suggested that by setting aside 256 bytes, for a vector table, IM2 could be effectively used. By loading a vector table with the same byte, no matter what value was found on the data bus, it would find the proper routine address. With this thought in mind, I dug out some old code I had been working on to provide a constant display of how much memory was available and a trace of basic program line numbers. I set up the routine to load a vector table and initialize IM2 upon entry. The routine will start by displaying the amount of free space available. By pressing enter and K, at the same time, the routine will switch to display line numbers as your Basic program runs. A delay has been built in so the line numbers can be read, you will notice a slowing down of your program’s execution. By pressing enter and J, at the same time, the routine will return to displaying free space. To stop the routine completely press enter and L at the same time. To start the routine or restart after pressing enter and L use `RANDOMIZE USR 65281`. I have provided a Basic program to load the code. Type it in and save it before running. Once keyed in, and saved, run the program to poke the code into memory. Save the code using `SAVE "memtrace" CODE 65021,464`. To start the routine use `RANDOMIZE USR 65281`. Any keying errors may cause your machine to crash so double check the data statements very carefully. I hope that this routine gives you a good example of how IM2 can be used and spurs you on to develop some good routines to share here. ## BASIC Listing — TS2068 Program: MEMTRACE ``` 10 CLEAR 65020 20 FOR C=65021 TO 65023 30 READ X: POKE C,X 40 NEXT C 50 FOR C=65281 TO 65484 60 READ X: POKE C,X 70 NEXT C 80 STOP 90 DATA 195,28,255 100 DATA 197,213,229,245,33,0,254,6,0,54,253,35,16,251,54,253,62,254,237,71 110 DATA 241,225,209,193,237,94,201,255,243,197,213,229,245,1,254,191,237,120,254,28 120 DATA 40,28,254,26,40,10,254,22,32,11,175,50,75,255,24,5,62,1,50,75 130 DATA 255,205,78,255,241,225,209,193,251,201,237,86,24,246,0,191,80,237,91,101 140 DATA 92,33,191,80,34,76,255,58,75,255,254,1,204,187,255,32,5,42,69,92 150 DATA 24,5,42,178,92,237,82,1,240,216,205,139,255,1,24,252,205,139,255,1 160 DATA 156,255,205,139,255,1,246,255,205,139,255,1,255,255,205,139,255,201,175,9 170 DATA 60,56,252,237,66,61,198,48,229,205,165,255,33,76,255,52,42,76,255,205 180 DATA 178,255,225,201,237,75,54,92,38,0,111,41,41,41,9,235,201,6,8,26 190 DATA 119,36,19,16,250,201,6,10,197,1,244,1,33,0,0,17,0,0,237 200 DATA 176,193,16,241,201 ``` ## Assembly Listing ``` INTERRUPT MODE 2 CLEAR 65020 RAND USER 65281 TO START FDFD-FDFF 65021-65023 JUMP ADDRESS FE00-FF00 65024-65280 VECTORS 'FD' FF01-FFFF 65281-65635 AVAILABLE 65021 C31CFF JP L1 JUMP TO START OF ROUTINE 65024 REM SPACE FOR VECTOR TABLE 65281 DEFS 65281-ORG 65281 C5 L250 PUSH BC SAVE 65282 D5 PUSH DE REGISTERS 65283 E5 PUSH HL 65284 F5 PUSH AF 65285 2100FE LD HL,65024 LOAD START OF VECTOR TAB 65288 0600 LD B,00 SET REG. B FOR LOOP 65290 36FD L251 LD (HL),253 LOAD DATA 65292 23 INC HL POINT TO NEXT BYTE 65293 10FB DJNZ L251 CONTINUE LOOP 65295 36FD LD (HL),253 LOAD LAST BYTE 65297 3EFE LD A,254 LOAD VALUE FOR INDEX REG 65299 ED47 LD I,A LOAD INDEX REG FOR 65024 65301 F1 POP AF 65303 E1 POP HL RESTORE 65303 D1 POP DE RESTORE 65304 C1 POP BC REGISTERS 65305 ED5E IM 2 TURN ON INTERRUPT MODE 2 65307 C9 RET 65308 FF L1 RST 56 65309 F3 DI DISABLE INTERRUPTS 65310 C5 PUSH BC SAVE 65311 D5 PUSH DE 65312 E5 PUSH HL REGISTERS 65313 F5 PUSH AF 65314 01FEBF LD BC,49150 CHECK KEYBOARD 65317 ED78 IN A,(C) READ KEY(S) PRESSED 65319 FE1C CP 28 ENTER AND 'L' 65321 281C JR Z,L5 YES, TURN OFF ROUTINE 65323 FE1A CP 26 ENTER AND 'K' 65325 280A JR Z,L2 YES, TURN ON TRACE 65327 FE16 CP 22 ENTER AND 'J' 65329 200B JR NZ,L3 NO, CHECK PRIOR SETTING 65331 AF XOR A YES, TURN TRACE 65332 324BFF LD (L6),A OFF 65335 1805 JR L3 GO SHOW MEMORY LEFT 65337 3E01 L2 LD A,01 SET SWITCH FOR TRACE 65339 324BFF LD (L6),A 65342 CD4EFF L3 CALL L8 GO DO SERVICE REQUIRED 65345 F1 L4 POP AF 65346 E1 POP HL RESTORE 65347 D1 POP DE 65348 C1 POP BC REGISTERS 65349 FB EI ENABLE INTERRUPTS 65350 C9 RET RETURN 65351 ED56 L5 IM 1 RESET INTERRUPT MODE 1 65353 18F6 JR L4 GO RETURN 65355 00 L6 DEFB 00 ROUTINE SWITCH 65356 BF50 L7 DEFW 20671 SCREEN DISPLAY ADDRESS 65358 ED5B655C L8 LD DE,(23653)START OF FREE SPACE 65362 21BF50 L9 LD HL,20671 RESTORE DISPLAY 65365 224CFF LD (L7),HL FILE 65368 3A4BFF LD A,(L6) ADDRESS 65371 FE01 CP 01 TRACE REQUIRED 65373 CCBBFF CALL Z,L17 YES, CALL TRACE ROUTINE 65376 2005 JR NZ,L10 NO, GO TO MEMORY ROUTINE 65378 2A455C LD HL,(23621)CURRENT STATEMENT NUMBER 65381 1805 JR L11 65383 2AB25C L10 LD HL,(23730)RAMTOP 65386 ED52 SBC HL,DE FIND MEMORY LEFT 65388 01F0D8 L11 LD BC,55536 65391 CD8BFF CALL L12 CALC. # OF 10,000 BYTES 65394 0118FC LD BC,64536 65397 CD8BFF CALL L12 CALC. # OF 1,000 BYTES 65400 019CFF LD BC,65436 65403 CD8BFF CALL L12 CALC. # OF 100 BYTES 65406 01F6FF LD BC,65526 65409 CD8BFF CALL L12 CALC. # OF 10 BYTES 65412 01FFFF LD BC,65535 65415 CD8BFF CALL L12 CALC. # OF UNIT BYTES 65418 C9 RET 65419 AF L12 XOR A CLEAR 65420 09 L13 ADD HL,BC ADD NEGATIVE VALUE 65421 3C INC A 65422 38FC JR C,L13 CONTINUE TILL NO CARRY 65424 ED42 SBC HL,BC RESTORE TO CORRECT VALUE 65426 3D DEC A DECREMENT BY ONE 65427 C630 ADD A,48 CONVERT DIGIT TO ASCII 65429 E5 PUSH HL SAVE HL REGISTERS 65430 CDA5FF CALL L14 GO FIND DIGIT 65433 214CFF LD HL,L7 INCREMENT SCREEN 65436 34 INC (HL) DISPLAY 65437 2A4CFF LD HL,(L7) ADDRESS 65440 CDB2FF CALL L15 GO PRINT DIGIT ON SCREEN 65443 E1 POP HL RESTORE HL REGISTERS 65444 C9 RET RETURN TO CALLER 65445 ED4B365C L14 LD BC,(23606)POINT TO CURR. CHAR. SET 65449 2600 LD H,0 ZERO REG. H 65451 6F LD L,A LOAD VALUE IN REG L 65452 29 ADD HL,HL DOUBLE 65453 29 ADD HL,HL DOUBLE AGAIN 65454 29 ADD HL,HL AND AGAIN 65455 09 ADD HL,BC GET CHAR. ADDRESS 65456 EB EX DE,HL SAVE IN REGS DE 65457 C9 RET RETURN TO CALLER 65458 0608 L15 LD B,08 65460 1A L16 LD A,(DE) MOVE CHARACTER TO SCREEN 65461 77 LD (HL),A 65462 24 INC H 65463 13 INC DE 65464 10FA DJNZ L16 LOOP UNTIL MOVED 65466 C9 RET RETURN TO CALLER 65467 060A L17 LD B,10 LOAD DELAY FACTOR 65469 C5 L18 PUSH BC 65470 01F401 LD BC,0500 ROUTINE TO 65473 210000 LD HL,0000 DELAY 65476 110000 LD DE,0000 FOR 65479 EDB0 LDIR TRACE 65481 C1 POP BC 65482 10F1 DJNZ L18 65484 C9 RET RETURN TO CALLER ``` ## Example Routine A relocatable skeleton of the same technique, for building your own IM2 routine. `START` marks where the service routine goes. ``` INTERRUPT MODE 2 CLEAR 64763 GIVES 484 BYTES FOR ROUTINES RAND USER 65025 TO START FCFC - FCFE 64764 - 64766 JUMP ADDRESS FD00 - FE00 64768 - 65024 VECTORS SET TO 'FC' FE01 - FE1B 65025 - 65051 STARTUP CODE FE1C - FFFF 65052 - 65535 AVAILABLE DEFS 64764-ORG JP 65052 JUMP TO START OF ROUTINE REM REM SPACE FOR VECTOR TABLE REM DEFS 65025-ORG INIT PUSH BC SAVE PUSH DE REGISTERS PUSH HL PUSH AF LD HL,64768 LOAD START OF VECTOR TABLE LD B,00 SET REG. B FOR LOOP LOOP LD (HL),252 LOAD DATA INC HL POINT TO NEXT BYTE DJNZ LOOP CONTINUE LOOP LD (HL),252 LOAD LAST BYTE LD A,253 LOAD VALUE FOR INDEX REG. LD I,A LOAD INDEX REG. FOR 64768 POP AF POP HL RESTORE POP DE REGISTERS POP BC IM 2 TURN ON INTERRUPT MODE 2 RET DEFS 65052-ORG START REM ``` *** ### Notes 1. The article gives the entry point as `RANDOMIZE USER 65281` in the text and `RAND USER 65025` in the Example Routine header. `USER` is not a Sinclair BASIC keyword; the statement is `RANDOMIZE USR`. 2. The assembly listing prints the address 65303 twice, against both `POP HL` and `POP DE`. `POP AF` at 65301 occupies one byte, so `POP HL` is at 65302; corrected here. The object bytes are unaffected and are confirmed by the DATA statements in the BASIC loader.