does your zeddy (or emulator) work like the real thing ?
Re: does your zeddy (or emulator) work like the real thing ?
Ah, that will explain it then. the effect of moving the entire creen up 1 scanline was by accident rather than design. The way my interrupt handler works at the top of the screen the nmi routine jumps to my code before generating the vsync, i then jump to the normal rom routine to genrate Vsync and read the keyboard but becuase the NMI routie has already pushed the main registers on the stack i have to find a way to control where thr rom routine returns too. so before jumping to the rom routine i manipulate the stack by putting IY (so that i can run code that uses IY) and a return address UNDER the 4 main registers on the stack, remeber the rom routine pops these main registers before returning.
so why does it move the display, because on a real zx81 Vsync does not reset/hold the hsync generator it continues to run just like it always does, only 2 things cause the Hsync to reset, a roll over from count 207 to 0 and an int ack (M1 low, and IORQ low) the upshot is that because of the extra time spent manipulating the stack we get an extra hsync that the character generator line counter counts after the vsync has ended. so on a real zeddy to counter this i decrease the number of blank lines in the top margin by 1 hence the entire display moves up by 1 line, i also increase the number of blank lines in the lower margin by 1 so overall display generation frequency remains the same.
i'll post the code later, im on the wrong PC at the moment.
Andy
so why does it move the display, because on a real zx81 Vsync does not reset/hold the hsync generator it continues to run just like it always does, only 2 things cause the Hsync to reset, a roll over from count 207 to 0 and an int ack (M1 low, and IORQ low) the upshot is that because of the extra time spent manipulating the stack we get an extra hsync that the character generator line counter counts after the vsync has ended. so on a real zeddy to counter this i decrease the number of blank lines in the top margin by 1 hence the entire display moves up by 1 line, i also increase the number of blank lines in the lower margin by 1 so overall display generation frequency remains the same.
i'll post the code later, im on the wrong PC at the moment.
Andy
what's that Smell.... smells like fresh flux and solder fumes...
Re: does your zeddy (or emulator) work like the real thing ?
Code: Select all
;===================================================
;= =
;= ZX81 interrupt handler, By Andrew Rea. =
;= =
;= due to the complex way the ZX81 generates its =
;= display during 'SLOW' mode if you wish to =
;= carry out a regular task at every interrupt =
;= you must manipulate the IX register which is =
;= used as a jump vector within the ZX81 rom. =
;= =
;= But to keep a steady display you must also =
;= either copy the rom code to generate the display=
;= or write your own code. =
;= =
;= this solution uses mostly the original rom. =
;= =
;= it also saves and restores the IY register, =
;= which is use in the rom code, normally you =
;= should not run USER code that uses the IY =
;= but since it is saved things seem to work ok =
;= =
;===================================================
;writtne for tasm assembler, with undocumented instructions
;supported.
;
; Compile with "tasm -80 -b input_source_code.asm output_binary_file.bin
;
;
#define db .byte ; TASM cross-assembler definitions
#define DB .byte
#define dw .word
#define DW .word
#define ds .block
#define DS .block
#define org .org
#define ORG .org
#define end .end
#define END .end
;=========================
;= =
;= you can change the =
;= following to suit the =
;= address of the PT3 =
;= player module. =
;= =
;=========================
PLAYER_START .EQU $2000
PLAYER_PLAY .EQU $2002
PLAYER_MUTE .EQU $2005
;this will be compiled as a ZX81 .p file
org $4009
;= System variables ============================================
db 0 ;VERSN
dw 0 ;E_PPC
dw dfile ;D_FILE
dw dfile+1 ;DF_CC
dw var ;VARS
dw 0 ;DEST
dw var+1 ;E_LINE
dw last-1 ;CH_ADD
dw 0 ;X_PTR
dw last ;STKBOT
dw last ;STKEND
db 0 ;BERG
dw membot ;MEM
db 0 ;not used
db 2 ;DF_SZ
dw 1 ;S_TOP
db $FF,$FF,$FF ;LAST_K
db 55 ;MARGIN
dw dfile ;NXTLIN
dw 0 ;OLDPPC
db 0 ;FLAGX
dw 0 ;STRLEN
dw $0C8D ;T_ADDR
dw 0 ;SEED
dw $FFFF ;FRAMES
db 0,0 ;COORDS
db $BC ;PR_CC
db 33,24 ;S_POSN
db %01000000 ;CDFLAG
ds 33 ;Print buffer
membot:
ds 30 ;Calculator´s memory area
ds 2 ;not used
;= First BASIC line, asm code ==================================
line0:
db 0,0
dw dfile-$-2
db $ea ;zx81 token REM
;= Your code should follow this file ==========================
;=
;= This is the intterupt handler
CONTROL:
DB $00 ;used as a way of getting a signal into the interrupt handler
;
;on initialise ' call start '
;
; CONTROL = 0
;
; 0~ DON'T CALL PLAYER DURRING INT
; BUT SILENCE SOUND.
;
; 1 ~ CALL PLAYER DURRING INT
;
; 255 ~ SILENCE SOUND AND
; STOP INTTERUPT HANDLER
PT3FILE_ADDRESS:
DW $8000 ;DEFAULT ADDRESS FOR PT3 FILE, ALTER THIS
;TO THE ADDRESS OF YOUR PT3 FILE
;THEN START THE HANDLER
START:
XOR A ;ZERO
LD (CONTROL),A ;STORE IN CONTROL BYTE
;AFTER INITIALISING
;PLAYER WILL NOT PLAY
;UNTIL USER ALTERS THIS BYTE
;TO = 1
GO_HANDLER:
TEST_X:
;LD A,IXL ;margin is still in top
; DB $DD,%01111101
; CP $81
; JR NZ,TEST_X ;top of screen
;LD A,IXL
TEST_X_2:
DB $DD,%01111101 ;test for bottom
CP $8F
JR NZ,TEST_X_2 ;
;AND THEN LOAD IX REGISTER SO OUR
LD IX,END_OF_BOTTOM_MARGIN
;HANDLER IS USED INSTEAD
INIT_PLAYER:
LD HL,(PT3FILE_ADDRESS)
CALL PLAYER_START ;INITIALISE THE PLAYER
RET ;BACK TO USERS PROGRAM
;=============================
;= =
;= DISPLAY INTTERUPT HANDLER =
;= =
;==================================================
;= =
;= The display intturupt handler has 2 main parts =
;= =
;= during user program execution the NMI int are =
;= processed by incrementing the a' register (from=
;= the af' pair ) and when zero is reached the =
;= main registers AF, BC, DE, HL are pushed onto =
;= the stack and a jump is made to address held =
;= in IX. The nmi's are active during the 'blank' =
;= area's at the top and bottom of the diaply =
;= these are the top and bottom margins.
;= =
;= So by altering IX we can take control of the =
;= display intterupt cycle =
;= =
;= 1) create a vsync signal and read keyboard. =
;= 1a) start top margin, and resume user program. =
;= =
;= 2) generate the display. =
;= 2a) start bottom margin, and resume user prog- =
;= gram =
;= =
;==================================================
;NOW THE TRICKY BIT !
;
;==========
;= =
;= PART 1 =
;= =
;==========
END_OF_BOTTOM_MARGIN:
;NMI ROUTINE JUMPS HERE AT THE END OF THE BOTTOM MARGIN.
;THIS REPLACES THE $028F JUMP.
;when we get here the NMI routine has already put AF, BC, DE, HL on the stack
;HL on last
;
; sp ---> HL
; DE
; BC
; AF
;nmi is also turned off
;but i want it to return here so i can alter IX again.
;so beacuase the rom routine will pop these off before RET-ing
;i need to get my return address under 4 words on the stack
;
LD HL, AFTER_VSYNC ;the address i wish to return to
;after the call to rom.
;RIGHT GONNA TRY A DIFFERENT APPROACH TO THIS.
;
;four items on stack...
POP AF ;HL IN AF, leaves 3
POP DE ;DE IN DE, leaves 2
POP BC ;BC IN BC, leaves 1
;AF STILL ON STACK
EX (SP),IY ;swap IY and final value on stack
;IY it could be any value by now...
PUSH HL ;THE RETURN ADDRESS where execution will
;continue after ROM code has run
PUSH IY ;AF BACK ON STACK
PUSH BC ;BC BACK ON STACK
PUSH DE ;DE BACK ON STACK
PUSH AF ;HL BACK ON STACK
;so now we have IY on the stack then our return address and then the original
;4 registers pushed by the NMI routine.
LD IY,$4000 ;SET IY FOR ROM CODE TO RUN CORRECTLY
JP $0229
;THIS ROM ROUTINE NORMALLY POPS THE REGISTERS AND
;RETURNS TO USER CODE EXECUTION
;WITH IX LOADED $0281, READY FOR NEXT VIDEO INT.
;BUT NOW IT RETURNS HERE, BECAUSE I SHOVED EXTRA STUFF
;ON THE STACK
AFTER_VSYNC:
START_OF_TOP_MARGIN:
;so we should have returned here
;with just IY left on the stack
POP IY
;NOW ALL THIS PUSHING AND POPPING MEANS WE HAVE MISSED THE FIRST HSYNC
;REMEBER HSYNC ARE NOT RESET BY VSYNC, BUT A NORMAL INT ACK.
;SO NOW ALL THE CHARACTERS ARE MOVED UP 1 PIXEL LINE (LINE COUNTER IN ula)
;SO MUST DECREMENT THE NMI INTERUPT COUNTER (IT ACTUALLY COUNTS UP)
;
;Ha Ha, I've known for a while that eightyone does not correctly
;handle the hsync timming. so the character are displayed wrong on eightyone.
;
;wonder if this will work on any other emulator correctly ?
;vb81xur displays it ok, but my test for IXL going to $8f doesn't seem
;to work on VB81xur
;originally was turning off nmi whilst adjusting the a' register
;but tried it without and it works just fine on real ZX81
;could be another place for emulators to fall over ;-)
; out ($fd),a ;TURN OFF nmi JUST INCASE AN NMI HAPPENS WITH THE
ex af,af' ;THE WRONG AF PAIR ACTIVE
inc a ;DECREMENT THE LINE COUNTER (YES IT COUNTS UP)
ex af,af' ;SWAP BACK TO NORMAL AF
; out ($fe),a ;AND TURN ON THE nmi AGAIN
RESET_IX_VECT: ;FINALLY WE ARE READY TO RETURN TO USER CODE
LD IX,END_OF_TOP_MARGIN ;SET THE IX REG READY FOR NEXT END OF TOP MARGIN
RET ;RETURN TO USER PROGRAM
END_OF_TOP_MARGIN:
;==========
;= =
;= PART 2 =
;= =
;==========
;NMI ROUTINE HAS NOW JUMPED HERE AT THE END OF THE TOP MARGIN
;NMI'S ARE OFF
;STACK IS AS BEFORE
;MUST PRETTY MUCH COPY ROM ELSE TOP FEW LINES OF DISPLAY GET CORRUPTED
LD A,R ; SAME AS
LD BC,$1901 ; ROM
LD A,$F5 ; CODE
CALL $02B5 ; BUT....
;RETURNS HERE WHEN DISPLAY IS DONE
START_OF_BOTTOM_MARGIN
PUSH IY ;SAVE iy ONCE AGAIN
LD a,($4028) ; get the margin from sys-vars
NEG ; Negate
; normal rom increments (one less margin line)
;INC A ; MISSING THIS INC COMPENSATES FOR THE ONE
; ONE LESS ABOVE
EX AF,AF' ; place negative count of blank lines in A'
LD IX,END_OF_BOTTOM _MARGIN ;AND MAKE SURE IX IS LOADED
OUT ($FE),A ; enable the NMI generator.
; THATS PRETTY MUCH THE INTERRUPT HANDLER
; main registers are still on the stack with IY on top.
;LETS PLAY SOME MUSIC ;-)
; IF (CONTROL) = 255 THEN ix LOADED WITH NORMAL ROM VECTOR (STOPS HANDLER RUNNING )
; (NEXT TIME NMI ROUTINE )
; (DOES A JP (IX) after )
; (after the top margin. )
; AND ALSO MUTES PLAYER.
;
; IF (CONTROL) = 0 THEN MUTES PLAYER.
;
; IF (CONTROL) = 1 THEN CALLS PLAYER EVERY 1/50TH SECOND
;
; IF (CONTROL) = 'other value' THEN DO NOTHING; SO SOUND CHIP WILL CONTINUE TO SOUND...
; LAST DATA SENT TO IT...
LD A,(CONTROL)
INC A ;TEST FOR 255
JR NZ,DONT_EXIT_INTS ;ONLY 255 WILL RSULT IN ZERO
EXIT_INTS:
LD IX,$028F ;NORMAL ix VECTOR
INC A ;TRICK NEXT TEST
DONT_EXIT_INTS:
exx
push hl
exx
DEC A ;TEST FOR ZERO
CALL Z,PLAYER_MUTE ;IF IT WAS 0 RESULT WILL BE ZERO
DEC A ;OR 1
CALL Z,PLAYER_PLAY ;OTHER VALUES WILL DO NOTHING
exx
pop hl
exx ;HERE
; THATS IT FOR THE PLAYER BIT.
POPS:
pop IY ;restored from entry to int routine
POP HL ;AND FINNALY RESTORE USERS REGISTERS
POP DE ;
POP BC ;
POP AF ;
;AND ENDS HERE
RET ; BACK TO USER PROG.
;=====================================
;= your code should end here ===================================
;zx81end.asm
;used at end of file....
db $76 ;N/L end of line 0
;- Display file --------------------------------------------
dfile:
db $76
db $76,$76,$76,$76,$76,$76,$76,$76
db $76,$76,$76,$76,$76,$76,$76,$76
db $76,$76,$76,$76,$76,$76,$76,$76
;- BASIC-Variables ----------------------------------------
var:
db $80
;- End of program area ----------------------------
last:
end
Andy
what's that Smell.... smells like fresh flux and solder fumes...
Re: does your zeddy (or emulator) work like the real thing ?
Aaaargh. Seems my homebrew Zeddy made from standard-logic-chips manages to emulate the emulators in real hardware:
The challenge was to build a ZX81-compatible with as few standard-ICs as possible. I knew I omitted some shifters in the sync-Logic, but why..? It will take me a while to understand that, if ever...
The challenge was to build a ZX81-compatible with as few standard-ICs as possible. I knew I omitted some shifters in the sync-Logic, but why..? It will take me a while to understand that, if ever...
Re: does your zeddy (or emulator) work like the real thing ?
Hi Oliver,
Thats a nice home brew you got there, gow many chips is it ? do you still have the schematics for it ?
But This is what i was expecting from homebrew machines, if my theory is correct, i did notice however that the first scanline is shifted to the left also.
Andy
Thats a nice home brew you got there, gow many chips is it ? do you still have the schematics for it ?
But This is what i was expecting from homebrew machines, if my theory is correct, i did notice however that the first scanline is shifted to the left also.
Andy
what's that Smell.... smells like fresh flux and solder fumes...
Re: does your zeddy (or emulator) work like the real thing ?
Hi Andy,
The Zeddy-board has 14 Chips + RAM+ROM+CPU. Schematics can be found here:
http://forum.tlienhard.com/phpBB3/viewt ... =331#p1647 (sorry, mostly in German, but you will find the ZX81_Clone_Schem.zip file with the schematics).
I already know that the HSync-Timing differs, making the board run few more cycles between the NMIs. Intermediately I improved that timing ( ZX81_Clone_2_Schem.zip, still 14 TTLs) but the wiring on the board became too complicated, so I reverted to the initial version. Thats the downside of using standard-logic - compared to FPGAs debugging is somewhat harder.
Oliver
The Zeddy-board has 14 Chips + RAM+ROM+CPU. Schematics can be found here:
http://forum.tlienhard.com/phpBB3/viewt ... =331#p1647 (sorry, mostly in German, but you will find the ZX81_Clone_Schem.zip file with the schematics).
I already know that the HSync-Timing differs, making the board run few more cycles between the NMIs. Intermediately I improved that timing ( ZX81_Clone_2_Schem.zip, still 14 TTLs) but the wiring on the board became too complicated, so I reverted to the initial version. Thats the downside of using standard-logic - compared to FPGAs debugging is somewhat harder.
Oliver
Re: does your zeddy (or emulator) work like the real thing ?
Bodo Wenzel also did a test with his "FPGA-Zeddy"-clone. And he has also the effect like on EO. Here are some pictures he sent to me:
Siggi
Siggi
My ZX81 web-server: online since 2007, running since dec. 2020 using ZeddyNet hardware
http://zx81.ddns.net/ZxTeaM
http://zx81.ddns.net/ZxTeaM
Re: does your zeddy (or emulator) work like the real thing ?
Bodo can fix it....
it's a simple fix for CPLD or FPGA....
It all revolves around the Hsync counter, Vsync does NOT STOP the hsync counter NOR does it reset it... only 2 things reset Hsync counter
1) a roll around from max-count back to zero
2) and int-ack (M1 and IORQ both low).
But also the hsyncs are generated 16 cycles after the reset.
i use the following code in my CPLD ULA which as far as i can tell works exactly like the real thing (yet to be proved wrong
)
So Hsync is generated when count reaches 16 thru to 31, also fed to NMI signal if NMI's are on.
It's a bit more trouble to fix 74xx series clones but not impossible
Andy
P.s That a really nice clone machine that Bodo has made
it's a simple fix for CPLD or FPGA....
It all revolves around the Hsync counter, Vsync does NOT STOP the hsync counter NOR does it reset it... only 2 things reset Hsync counter
1) a roll around from max-count back to zero
2) and int-ack (M1 and IORQ both low).
But also the hsyncs are generated 16 cycles after the reset.
i use the following code in my CPLD ULA which as far as i can tell works exactly like the real thing (yet to be proved wrong

Code: Select all
reg [7:0]hc;
wire hc_reset;
assign hc_reset = (!m1 & !iorq);
always @ (negedge slow_clock) begin
if (hc_reset | hc == 206) begin
hc <= 8'd0 ;
end else begin
hc <= hc + 8'd1 ;
end
end
wire hsync;
assign hsync = !hc[7] & !hc[6] & !hc[5] & hc[4] ;
It's a bit more trouble to fix 74xx series clones but not impossible

Andy
P.s That a really nice clone machine that Bodo has made

what's that Smell.... smells like fresh flux and solder fumes...
-
- Posts: 108
- Joined: Mon May 23, 2011 2:10 pm
- Location: A bit north of Cardiff, Wales.
- Contact:
Re: does your zeddy (or emulator) work like the real thing ?
Yeah, I was going to do that with my NMI gen, but haven't managed to do it with a low chip count (but have got it working with more chips).
That is, reset on INTACK then 16 cycle pulse 16 cycles after the INTACK ...that's what I measured on the real ZX81 when I did the previous version.
I want to keep the chip count no higher than 6 (currently 5 chips for the VSYNC reset version). I'll keep on trying, and will post if successful
That is, reset on INTACK then 16 cycle pulse 16 cycles after the INTACK ...that's what I measured on the real ZX81 when I did the previous version.
I want to keep the chip count no higher than 6 (currently 5 chips for the VSYNC reset version). I'll keep on trying, and will post if successful
