type in to learn about IM2

I'm trying to mess around with learning about IM2 and I found a nice little article in Sinclair User September 1988, issue 78, Page 70-71 https://worldofspectrum.org/archive/magazines/sinclair-user/78/0/1988/9/0.
Nice article, but the type in has some sort of bug in it and I haven't been able to figure out what it is.

The code is
org $ff01
;;issue 78
;;print usr 65285

;;ff05
HOURS:
	defb 0
MINUTES:
	defb 0
SECONDS:
	defb 0
FIFTIES:
	defb 0	;interupt counter
	
clock_on:	
	jr INT_ON	;on entry point


clock_off:
	di			;disable maskable interupts
	ld A, $3f
	ld I, A
	im 1
	ei
ret

INT_ON:
	di
	ld A, $fe
	ld I, A
	im 2
	;
	ld HL, $fe00
	
INT10:
	ld (HL), $fd
	inc L
	jr nz, INT10
	inc H
	ld (HL), $fd
	ld A, $c3
	ld ($fdfd), A
	ld HL, INT_ROUTINE	;;different
	ld ($fdfe), HL
	ld HL, FIFTIES
	ld (HL), 50
	ei
ret

INT_ROUTINE:
	rst $38
	push AF
	push BC
	push DE
	push HL
	call CLOCK
	pop HL
	pop DE
	pop BC
	pop AF
	ei
ret

CLOCK:
	ld HL, $5818
	ld DE, $5819
	ld BC, 7
	ld (HL), $57	;;color of attribute  different
	ldir
	ld HL, FIFTIES
	dec (HL)
	jr nz, PRINT_TIME
	ld (HL), 50	
	ld A, 59
	dec HL
	inc (HL)
	cp (HL)
	jr nc, PRINT_TIME
	ld (HL), 0
	dec HL
	inc (HL)
	cp (HL)
	jr nc, PRINT_TIME
	ld (HL), 0
	dec HL
	ld A, 23
	inc (HL)
	cp (HL)
	jr nc, PRINT_TIME
	ld (HL), 0

PRINT_TIME:
	ld DE, $4018
;	ld A, (HOURS)
;	call PRINT_DEC
;	ld A, $3a;; = :
;	call PRINT
;	ld A, (MINUTES)
;	call PRINT_DEC
;	ld A, $3a;; = :
	call PRINT
	ld A, (SECONDS)
	
PRINT_DEC:
	ld B, $2f

PD10:
	inc B
	sub 10
	jr nc, PD10
	add A, $3a
	push AF
	ld A, B
	call PRINT
	pop AF
	
PRINT:
	ld L, A
	ld H, 0
	add HL, HL
	add HL, HL
	add HL, HL
	ld A, H
	add A, $3c
	ld H, A
	ld B, 8
	ld C, D

PR10:
	ld A, (HL)
	ld (DE), A
	inc HL
	inc D
	djnz PR10
	ld D, C
	inc E
ret

I am using PASMO to compile it with the string
pasmo -v --tapbas clock.asm clock.tap

Looking for help on what is going wrong and how to fix it.

Thanks
Andy

Comments

  • I think you may be having a Pasmo issue rather than anything else... First let me say I don't use Pasmo... Just had a quick peek at Pasmo documentation... I can't see you setting the entry point... If Pasmo defaults to the start then it won't matter TOO much because you're starting with some "defb 0" which are NOPs... But... Bigger issue is from what I've read Pasmo "tapbas" feature generates BASIC that does a CLEAR of the first byte assembled (FF01 in this case). Problem is the code writes into memory preceding this address, FDFD to FDFF being set to a JP instruction then FE00 to FEFF being set to FD, so IM2 is guaranteed to "hit" FDFD when triggered. Running it through my mind the tap will load the basic, CLEAR, load the machine code "above" the CLEAR, run the code, which immediately corrupts the stack, tries to return to basic, and I'm guessing crashes? If so, if Pasmo allows multiple ORG directives, maybe try adding "org $fd00 / defb 0" right at the start? It'll force the BASIC code to give the routine plenty of space.... But as I said, I don't use Pasmo...
  • There's nothing wrong with the code itself here - the problem lies in the BASIC loader generated by Pasmo.
    10 CLEAR 65280
    20 POKE 23610,255
    30 LOAD ""CODE
    
    This BASIC program will only reserve memory locations from 65281 and upwards ($ff01 in hexadecimal). The CPU stack grows downwards from 65280 ($ff00). The code you're using writes its interrupt vector table and interrupt service routine in the memory from $fdfd to $ff00. This consequently destroys the CPU stack, leading to a crash.

    To fix the problem, all you need to do is CLEAR from 65020 or lower. You can't directly customise the BASIC generated by Pasmo, but you can put a few dummy bytes at $fdfd to fool it into generating the CLEAR statement at the correct place. Something like this should do:

    org $fdfd
    db 0
    
    ; rest of code...
    
    Host of CSSCGC 2020
    Currently working on Postie's Peril, a point-and-click adventure game for the 48K Spectrum made with my ZX Adventure Designer engine.
  • Oh I remember I learned IM2 with this too. It's a really good tutorial. I remember I didn't had an assembler back then so I just typed the numbers. (But IIRC the ones in the magazine had a bug or two.)

    My suggestion is to use MERGE to the file that is generated with Pasmo.

    For example:

    40 CLEAR 65020
    50 PRINT USR 65285
    MERGE ""
  • edited July 31
    hi
    its not pasmo who made a wrong start adres
    thats the PROGRAMMER who did that
    if changing the entry works, thats good, but still not the problem off pasmo !

    btw
    in your above version there is at least 1 code error by which your shortcut with ";" wont work
    ok
    PRINT_TIME:
    	ld DE, $4018
    ;	ld A, (HOURS)
    ;	call PRINT_DEC
    ;	ld A, $3a;; = :
    ;	call PRINT
    ;	ld A, (MINUTES)
    ;	call PRINT_DEC
    ;	ld A, $3a;; = :
    	call PRINT
    	ld A, (SECONDS)
    

    this is what is does
    PRINT_TIME:
    	ld DE, $4018
    	call PRINT
    	ld A, (SECONDS)
    
    you shortcut starts with printing the LAST KNOWN 'a'
    BUT the code FIRST loads A and THEN does a print
    you shortend you this to much OR to few like you should blocked that call aswell since SEconds will be printed severall lines lower.

    (edit:) and actualy for a tutorial type off artical they SHOULD have mentioned 2 problems clearly
    1) the actual FDFD jump has to be protected aswell
    the article JUST mentions "besure the ramtop"
    but thats NOT to be found in the ACTUAL code itself. its more an extra remark at the side.
    with this comes the second problem
    2)WHERE do you store the actual jump table and the actual jump itself
    although the comment in the asm tell, but it does not explain that its a problem if done wrong.

    its a tutorial so, they should have explained that properly and especially that a jumptable needs an exact location that TAKES SPACE AS WELL....
    so, it would have been much more CLEAR if they had written the total asm, up FROM 0xFDFD
    then a proper org 0xFDFC would have been made, with wich pasmo would have done a proper assembling
    cheers
    Post edited by Crisis on
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited July 31
    It's totally pasmo's problem. The code isn't wrong and the start address isn't wrong. Only the CLEAR address in the pasmo BASIC loader is wrong, which is not part of the Sinclair User article. Neither TAP files not pasmo existed in 1988. It's common for code to generate bytes in memory at runtime that aren't considered part of the code and shouldn't be loaded by any loader.

    The article explicitly says "ensure RAMTOP has been moved down to at least 65020", and the OP chose to use a crappy modern crossassembler that generates loaders which can't be controlled without assembling extra bytes that aren't needed in the output file. To be fair to pasmo, that is at least documented: "The Basic loader does a CLEAR before the initial address of the code". But there's no particular reason why --tapbas couldn't be written to take an argument for the CLEAR, or the END directive couldn't be overloaded with an optional second parameter.
    Post edited by colonel32 on
    Robin Verhagen-Guest
    SevenFFF / Threetwosevensixseven / colonel32
    NXtel NXTP ESP Update ESP Reset CSpect Plugins
  • edited July 31
    I think this tutorial should have explained the RAM use better and thus setting the ramtop, which is a part of the article since it does give the correct ramtop after all. And about pasmo, which other assemblers makes loaders? since then i can compare better if using the ORG information is an accurate matter or not. On which information should it fall back?
    the solution from PROSM works good. If the article was complete it would have given the jump instruction on that spot written already, and it was explained that following inbetween gap is a perfect place to set a variable table.if there is a gap.
    Post edited by Crisis on
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • With respect, it’s not Pasmo’s fault, or a fault with the code, or the writer of the article’s fault.

    It’s simply an error caused by using a (relatively) modern tool to do a job it was not designed to do.

    At the end of the day, as someone who is writing low level code, it is up to the programmer to fully understand what is going on. Then select the appropriate tool(s) for the job. And if needed, adjust parameters or the code if there are limitations in the tools. Or select alternative tools if the originally selected tool(s) don’t perform the required tasks to the requirements.

    Mark
  • Blame Canada?
  • RobeeeJay wrote: »
    Blame Canada?

    With all their hockey hullabaloo . . .
    Every man should plant a tree, build a house, and write a ZX Spectrum game.

    Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
    and zasm Z80 Assembler syntax highlighter.
    Member of the team that discovered, analyzed, and detailed the floating bus behavior on the ZX Spectrum +2A/+3.

    A few Spectrum game fixes.
  • edited August 1
    Thanks for helping me with this.

    I do have it working with your suggestions. I placed a link that has the compiled solution using PASMO and BAS2TAP.

    https://1drv.ms/u/s!Atc34t6eCvqj1nh-Q7kCczMrXv-N?e=Uhlp79

    @bhandscomb I had assumed that when I set the org in PASMO that it set the program start, but it was my lack of understanding of not only PASMO, but of the routine.

    @PROSM Your suggestion prompted me to start looking at BAS2TAP. Where I could make my own loader. Thanks for the suggestion.

    @Timmy. I started out with the type in, doing the pokes, there are at least 2 typo's in the printed article. One with the 259 and one with a 256, but probably more. In the ASM portion at least one pops out in PRINT_DEC, a magazine typo as LD, B $2F.

    @Crisis Yes, it was indeed my fault, in my defense I am learning as I have not really directly worked with IM2. Overall, I think it is a great article, I was missing a few bits which obviously threw me off.
    My mistake on placing comments in front of those lines as well as I was trying to poke around and shouldn't have left them in what I posted.

    @colonel32 Along with PROSM suggestion, I am now avoiding PASMO's loader and just spitting out the binary, combining it with BAS2TAP to output a loader. I had made an assumption about the loader and I was wrong and befuddled.

    @1024MAK Yes indeed it's my fault, however the article is a bit blurred and not quite as clear as it could have been in respect to the clear point IMHO. The majority of readers at this point were kids and whereas some kids were able to understand what was going on, I'm sure others weren't. I fall into the later category :).

    @RobeeeJay and @Ast_A_Moore, HEY! We love Canada, up here in Upstate New York (Except their darn weather they toss down to us). They can keep their Arctic Cyclones all to themselves.
    Post edited by andydansby on
  • andydansby wrote: »
    Thanks for helping me with this.

    I do have it working with your suggestions. I placed a link that has the compiled solution using PASMO and BAS2TAP.

    @Crisis Yes, it was indeed my fault, in my defense I am learning as I have not really directly worked with IM2. Overall, I think it is a great article, I was missing a few bits which obviously threw me off.
    My mistake on placing comments in front of those lines as well as I was trying to poke around and shouldn't have left them in what I posted.

    Hi
    I wouldnt call it 'a fault' but with this code as presented only 1 ';' more or one less would have helpt. Meanwhile we have a good discusion and see different sides of the same problem. I had and have moments personally and showed more then one miscode only to find out real mistakes and extra typos in my treads.
    If you have your clock working you can try outer stuff like sound off clours shadings, whatever. Have fun
    BTW, is the typin on TFFn?

    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • Right now, I only have the type in on the onedrive link. I looked for that type in first there.

    What I'm curious about is why it does not work on the 128k. One the original and on the +2, crash and rain effect and on the +2a and +3, just pure crash.
  • Don’t forget that on the 128k models some of the RAM can be swapped between different banks. The ROM changes both the ROM banks and the RAM banks.

    If the relevant bank of RAM is not in the Z80 memory map at the time that the interrupt is detected by the Z80, it will either fetch a different vector (from a different bank to where you put it), or the vector will point to a bank that does not have you code in it.

    To use the code unchanged, you need to use either 48K mode or ensure that both the location of the vector and the interrupt code pointed to by the vector is in an area that will be accessible by the Z80 whenever the interrupt may occur. But it can’t be in contended RAM.

    The memory map of the 128K / +2 is on this page (also here).

    So as you can see, it all has to be in RAM bank 2.

    On the +2A/+2B/+3/+3B it’s similar as long as the machine is not in special mode.

    You also have to ensure that the correct ROM is paged in if you are jumping (RST) to it.
    If you change banks during your routine, make sure that you restore the banks before returning.

    Mark


  • Oh, the routine works on the 128k models too, as long as you don't go back to the editor.

    So if you never leave the program and do something like 9999 GOTO 9999 then it would work.

    The 128K editor uses the upper memory so you can't really put a interrupt mode there.

    Therefore, a 48K game with interrupt at that location would still work, and if you really want to use more memory, you could relocate the interrupt routine (not a lot of work), or just disable the interrupts before you do something special with the 128k memory.
  • fill in the jump table before going into IM 2 . If an interrupt happens before you have filled in the table fun will happen
  • seedy1812 wrote: »
    fill in the jump table before going into IM 2 . If an interrupt happens before you have filled in the table fun will happen

    That shouldn't matter as interrupts are disabled whilst the table is being built up, so no IM2 interrupts.will happen till everything is in place.
  • Yes, ei/di controls whether interrupts are enabled, separately from ld i,a/im0/im1/im2 changing the mode.

    You can safely set the mode before you set i or create the vector table, provided interrupts are not enabled.
    Robin Verhagen-Guest
    SevenFFF / Threetwosevensixseven / colonel32
    NXtel NXTP ESP Update ESP Reset CSpect Plugins
Sign In or Register to comment.