Jump to content
IGNORED

Any info on Video Technology Laser 500 computer?


31336haxx0r

Recommended Posts

I've extended the emulator to work with double sided disks :-) Yes the tracks are reversed on the second side, I guess it makes sense to minimize head movements and also for backward compatibility.

I've also added some debug features for the disk drive so you can see exactly how it works. From the JavaScript console modify the variables:

fdc_debug_move = true; // debugs movements of the drive head
fdc_debug_data_size = true; // debugs changes in 8/16 bit flag
fdc_debug_read = true; // debugs byte reads
fdc_debug_write = true; // debugs byte writes
fdc_debug_side = true; // debugs changes in disk side (0/1)

The self-sync bit flag seems to be either 255 (on) or 213 (off) but there are less ONs that OFFs, suggesting that the controller switches automatically to ON somewhere.

Link to comment
Share on other sites

Hi Nippur72,

 

 

I've extended the emulator to work with double sided disks :-) Yes the tracks are reversed on the second side, I guess it makes sense to minimize head movements and also for backward compatibility.

The self-sync bit flag seems to be either 255 (on) or 213 (off) but there are less ONs that OFFs, suggesting that the controller switches automatically to ON somewhere.

 

 

Nice work on the double-sided code. Works fine here for me!

 

Looking at the read/write code, I think that whenever the *WRREQ bit (bit 6 in port $10) is turned ON, the controller defaults to writing in self-sync mode.

 

Writing $FF (255) to port $11 turns self-sync *ON*.

Writing *any other* value to port $11 turns self-sync *OFF*.

 

I think the 213 ($D5) value is just incidental, as the A register happens to be holding $D5 (next byte written after the self-sync sequence).

 

---

 

It's interesting to note that the self-sync flag is turned off *after* the $D5 byte is actually written to the data output register.

 

That suggests the self-sync flag is not sampled by the FDC prior to the byte being output, but can be changed mid-byte.

 

I'm presuming the $D5 byte is *not* written as a 10 bit byte? I don't have the real hardware to test unfortunately.

 

(It doesn't actually matter either way if the $D5 ID byte is written as 8 or 10 bits, it will still just magically work :) )

 

RAM:66BF D3 10 out (10h), a ; turn on *WRREQ - self-sync *on* by default.
RAM:66C1 7A ld a, d ; D = $FF here
RAM:66C2 D3 13 out (13h), a
RAM:66C4 loc_66C4:
RAM:66C4 CD 11 79 call WRITE_DISK_BYTE_D
RAM:66C7 10 FB djnz loc_66C4 ; Write $FF 127 times on first loop, sector_gap on rest
RAM:66C9 16 D5 ld d, 0D5h
RAM:66CB CD 11 79 call WRITE_DISK_BYTE_D
RAM:66CE D3 11 out (11h), a ; self-sync *off*
RAM:66D0 16 AA ld d, 0AAh
RAM:66D2 CD 11 79 call WRITE_DISK_BYTE_D
RAM:66D5 16 96 ld d, 96h

---

 

Here is the current state of my disassembly of DOS1.1:

http://crisis.com.au/images/LASER_DOS_1.1_DISS.zip

 

Includes the Boot Sector at $A200

Main DOS from $5E00-$7FFF (loaded into bank#6, executed in slot#1)

High memory routines copied to $FEE0-$FFAD

 

I've concentrated more on the read/write routines than on the high-level BASIC stuff,

but it should be reasonably easy to follow.

 

Regards,

Leslie

Link to comment
Share on other sites

  • 3 weeks later...

Hi James, et al.

 

The BASIC with the 500 appears to be pretty good but the way the first letter of the tokens are stored seems unique. At least I haven't seen anything like it before.

 

Maybe some sort of logic or math operation with it's position in the table?

 

 

 

The tokeniser routine at $2509 in the ROM as it processes the input line, uses the first ascii character it finds

as an index into a 26 word pointer table, for A-Z:

 

 

RAM:2509 TOKENIZE: ; CODE XREF: sub_2457+7D↑j
RAM:2509 ; sub_2457+93↑j
RAM:2509 E1 pop hl ; convert basic keyword to 1 byte TOKEN
RAM:250A CD 15 31 call sub_3115
RAM:250D E5 push hl
RAM:250E 21 E9 1B ld hl, KEYWD_PTR_ARRAY ; 26 char table, first letter of each
RAM:2511 D6 41 sub 41h ; 'A' ; A now ZERO OFFSET into table
RAM:2513 87 add a, a
RAM:2514 4F ld c, a
RAM:2515 06 00 ld b, 0
RAM:2517 09 add hl, bc
RAM:2518 5E ld e, (hl)
RAM:2519 23 inc hl
RAM:251A 56 ld d, (hl) ; DE now points at inividual letter table
RAM:251B E1 pop hl
RAM:251C 23 inc hl
....

 

 

RAM:1BE9 1D 1C KEYWD_PTR_ARRAY:dw KEYWORDS_A ; DATA XREF: sub_2457+B7↓o
RAM:1BEB 2E 1C dw KEYWORDS_B
RAM:1BED 2F 1C dw KEYWORDS_C
RAM:1BEF 83 1C dw KEYWORDS_D
RAM:1BF1 B0 1C dw KEYWORDS_E
RAM:1BF3 D1 1C dw KEYWORDS_F
RAM:1BF5 E7 1C dw KEYWORDS_G
RAM:1BF7 FB 1C dw KEYWORDS_H
RAM:1BF9 00 1D dw KEYWORDS_I
RAM:1BFB 1C 1D dw KEYWORDS_J
RAM:1BFD 20 1D dw KEYWORDS_K
RAM:1BFF 28 1D dw KEYWORDS_L
RAM:1C01 5C 1D dw KEYWORDS_M
RAM:1C03 81 1D dw KEYWORDS_N
RAM:1C05 94 1D dw KEYWORDS_O
RAM:1C07 AA 1D dw KEYWORDS_P
RAM:1C09 C8 1D dw KEYWORDS_Q
RAM:1C0B C9 1D dw KEYWORDS_R
RAM:1C0D 0A 1E dw KEYWORDS_S
RAM:1C0F 47 1E dw KEYWORDS_T
RAM:1C11 62 1E dw KEYWORDS_U
RAM:1C13 6B 1E dw KEYWORDS_V
RAM:1C15 7B 1E dw KEYWORDS_W
RAM:1C17 93 1E dw KEYWORDS_X
RAM:1C19 97 1E dw KEYWORDS_Y
RAM:1C1B 98 1E dw KEYWORDS_Z
RAM:1C1D 55 KEYWORDS_A: db 'U' ; DATA XREF: RAM:KEYWD_PTR_ARRAY↑o
RAM:1C1E 54 db 'T'
RAM:1C1F CF db 0CFh
RAM:1C20 AB db 0ABh ; AUTO $AB
RAM:1C21 4E db 'N'
RAM:1C22 C4 db 0C4h
RAM:1C23 F7 db 0F7h ; AND $F7
RAM:1C24 42 db 'B'
RAM:1C25 D3 db 0D3h
RAM:1C26 06 db 6 ; ABS $06
RAM:1C27 54 db 'T'
RAM:1C28 CE db 0CEh
RAM:1C29 0E db 0Eh ; ATN $0E
RAM:1C2A 53 db 'S'
RAM:1C2B C3 db 0C3h
RAM:1C2C 15 db 15h ; ASC $15
RAM:1C2D 00 db 0
RAM:1C2E 00 KEYWORDS_B: db 0 ; DATA XREF: RAM:1BEB↑o
RAM:1C2F 4C KEYWORDS_C: db 'L' ; DATA XREF: RAM:1BED↑o
RAM:1C30 4F db 'O'
.... and so on.
Following program will list all the keywords and their corresponding single-byte tokens:
10 A=&H1C1D
20 C=&H40
30 C=C+1
40 B=PEEK(A)
50 IF B=0 THEN A=A+1:GOTO 30
60 PRINT CHR$©;
70 IF B > 127 THEN 110
80 PRINT CHR$(B);
90 A=A+1
100 B=PEEK(A):GOTO 70
110 B=(B AND 127)
120 PRINT CHR$(B),
130 A=A+1
140 B=PEEK(A)
150 PRINT" Token:$";HEX$(B)
160 A=A+1
170 IF A < &H1E96 THEN 40
Still working on discovering all the entry points for the BASIC commands and keywords.
Regards,
Leslie
Link to comment
Share on other sites

 

Still working on discovering all the entry points for the BASIC commands and keywords.

 

do you already know about "basck" ? it's tool in the Z88DK compiler that automatically scans a ROM dump and finds MS basic entry points:

 

# File size: 32768

# Specific Z80 CPU code detected

# Microsoft 8080/Z80 BASIC found
#  Extended syntax detected (classic version)
#  Double precision maths detected
#  Microsoft signature not found

BASTXT 	= $8041   ; BASIC program start ptr (aka TXTTAB)


#    CPDEHL (compare DE and HL), code found at $5FA1
#    (Detected position for ORG:  0)

INPORT 	= $8579   ; Current port for 'INP' function
OTPORT 	= $857C   ; Current port for 'OUT' statement
SEED 	= $8586   ; Seed for RND numbers
LSTRND2 	= $8580   ; Last RND number
BUFFER 	= $8149   ; Start of input buffer
TMSTPT 	= $839F   ; Temporary string pool pointer
TMPSTR 	= $83BF   ; Temporary string
NXTOPR 	= $83E3   ; Address ptr to next operator
PROGND 	= $83E9   ; BASIC program end ptr (aka VARTAB)
VAREND 	= $83EB   ; End of variables
ARREND 	= $83ED   ; End of arrays (lowest free mem)
SGNRES 	= $852F   ; Sign of result
TEMPST 	= $83A1   ; (word), temporary descriptors
TEMPPT 	= $839F   ; (word), start of free area of temporary descriptor
PRMLEN 	= $840D   ; (word), number of bytes of obj table
NOFUNS 	= $84DE   ; (byte), 0 if no function active
PRMLN2 	= $8475   ; (word), size of parameter block
FUNACT 	= $84E1   ; (word), active functions counter
PRMSTK 	= $840B   ; (word), previous block definition on stack
SUBFLG 	= $83CC   ; (byte), flag for USR fn. array
TEMP 	= $83CE   ; (word) temp. reservation for st.code
VALTYP 	= $838E   ; (word) type indicator
PRITAB 	= $1EAE   ; (word) Arithmetic precedence table
TEMP2 	= $83E3   ; (word) temp. storage used by EVAL
TEMP3 	= $83C4   ; (word) used for garbage collection or by USR function
SAVTXT 	= $83D6   ; (word), prg pointer for resume
TEMPST 	= $83A1   ; (word), temporary descriptors
TEMPPT 	= $839F   ; (word), start of free area of temporary descriptor
CURLIN 	= $803F   ; (word), line number being interpreted
OLDLIN 	= $83E5   ; (word), old line number set up ^C ...
SAVTXT 	= $83D6   ; (word), prg pointer for resume
OLDTXT 	= $83E7   ; (word), prg pointer for CONT


FPREG 	= $852B   ; Floating Point Register (FACCU, FACLOW on Ext. BASIC)
FPEXP 	= $852E   ; Floating Point Exponent
DBL_FPREG 	= $852B   ; Double Precision Floating Point Register (aka FACLOW)
DBL_LAST_FPREG 	= $853A   ; Last byte in Double Precision FP register (+sign bit)

CPDEHL 	= $5FA2   ; compare DE and HL
FNDNUM 	= $3507   ; Load 'A' with the next number in BASIC program
GETINT 	= $350A   ; Get a number to 'A'
DEPINT 	= $34EF   ; Get integer variable to DE, error if negative
FPSINT 	= $34E9   ; Get subscript
POSINT 	= $34EC   ; Get positive integer
GETVAR 	= $59B7   ; Get variable address to DE
DIM 	= $59B2   ; DIM command
CHKSTK 	= $5E9E   ; Check for C levels of stack
OPRND 	= $304E   ; Get next expression value
SYNCHR 	= $5FA8   ; Check syntax, 1 byte follows to be compared
LFRGNM 	= $655B   ; number in program listing and check for ending ')'
HLPASS 	= $3DFA   ; Get back from function passing an INT value HL
MIDNUM 	= $6560   ; Get number in program listing
INT_RESULT_A 	= $3C6F   ; Get back from function, result in A (signed)

GETYPR 	= $320F   ; Test number FAC type (Precision mode, etc..)
TSTSGN 	= $3C35   ; Test sign of FPREG
_TSTSGN 	= $3C76   ; Test sign in number
INVSGN 	= $3C64   ; Invert number sign
STAKFP 	= $3C88   ; Put FP value on stack
NEGAFT 	= $49F9   ; Negate number
LOG 	= $3AC0   ; LOG
EXP 	= $4A63   ; EXP
TAN 	= $4C4C   ; TAN
ATN 	= $4C61   ; ATN
DBL_ABS 	= $3FC6   ; ABS (double precision BASIC variant)
RND 	= $4B14   ; RND
SUBCDE 	= $3999   ; Subtract BCDE from FP reg
FPADD 	= $399C   ; Add BCDE to FP reg
SCALE 	= $3A6B   ; Scale number in BCDE for A exponent (bits)
PLUCDE 	= $3A4B   ; Add number pointed by HL to CDE
COMPL 	= $3A57   ; Convert a negative number to positive
PHLTFP 	= $3C95   ; Number at HL to BCDE
FPBCDE 	= $3C98   ; Move BCDE to FPREG
MLSP10 	= $3C1E   ; Multiply number in FPREG by 10
FPMULT 	= $3B05   ; Multiply BCDE to FP reg
DIV10 	= $3B5D   ; Divide FP by 10
DIV 	= $3B66   ; Divide FP by number on stack
DCBCDE 	= $3E48   ; Decrement FP value in BCDE
BCDEFP 	= $3CA3   ; Load FP reg to BCDE
LOADFP 	= $3CA6   ; Load FP value pointed by HL to BCDE
CMPNUM 	= $3CF1   ; Compare FP reg to BCDE
FPINT 	= $3E24   ; Floating Point to Integer
FLGREL 	= $3C44   ; CY and A to FP, & normalise
INT 	= $3E6E   ; INT
DBL_SUB 	= $3FEC   ; Double precision SUB (formerly SUBCDE)
DBL_ADD 	= $3FF3   ; Double precision ADD (formerly FPADD)
FIX 	= $3E4F   ; Double Precision to Integer conversion
INT_MUL 	= $3F29   ; Integer MULTIPLY
MLDEBC 	= $3EE1   ; Multiply DE by BC
_ASCTFP 	= $42A0   ; ASCII to FP number
H_ASCTFP 	= $429B   ; ASCII to FP number (also '&' prefixes)
PRNUMS 	= $62D2   ; Print number string
PRS 	= $62D3   ; Create string entry and print it
PRS1 	= $62D6   ; Print string at HL
STR 	= $624C   ; STR BASIC function entry
SAVSTR 	= $6255   ; Save string in string area
MKTMST 	= $626F   ; Make temporary string
CRTMST 	= $6272   ; Create temporary string entry
SSTSA 	= $6437   ; Move string on stack to string area
TOSTRA 	= $643F   ; Move string in BC, (len in L) to string area
TSALP 	= $6440   ; TOSTRA loop
FDTLP 	= $2EA7   ; Find next DATA statement
DATA 	= $29EA   ; DATA statement: find next DATA program line..
RESTOR 	= $5FBA   ; 'RESTORE' stmt, init ptr to DATA program line..
NEW_STMT 	= $27B5   ; Interprete next statement
GO_TO 	= $2993   ; Go To..
MAKINT 	= $350D   ; Convert tmp string to int in A register
CONCAT 	= $63FF   ; String concatenation
TESTR 	= $62EB   ; Test if enough room for string
TOPOOL 	= $649E   ; Save in string pool
TSTOPL 	= $62AD   ; Temporary string to pool
EVAL 	= $2ED4   ; (a.k.a. GETNUM, evaluate expression (GETNUM)
EVAL1 	= $2ED7   ; Save precedence and eval until precedence break
EVAL3 	= $2EE9   ; Evaluate expression until precedence break
CRTST 	= $627D   ; Create String
QTSTR 	= $627E   ; Create quote terminated String
DTSTR 	= $6281   ; Create String, termination char in D
GETSTR 	= $6448   ; Get string pointed by FPREG 'Type Error' if it is not
GSTRCU 	= $644B   ; Get string pointed by FPREG
GSTRHL 	= $644E   ; Get string pointed by HL
GSTRDE 	= $644F   ; Get string pointed by DE
TSTSTR 	= $3E1D   ; Test a string, 'Type Error' if it is not

LNUM_RANGE 	= $241A   ; Read numeric range function parameters
LNUM_PARM 	= $2921   ; Read numeric function parameter
_CHRGTB 	= $281A   ; Pick next char from program
_CHRCKB 	= $281B   ; Pick current char (or token) on program
UCASE_HL 	= $3115   ; Get char from (HL) and make upper case
UCASE 	= $3116   ; Make char in 'A' upper case
RINPUT 	= $0C1C   ; Line input
OUTC 	= $57D9   ; Output char in 'A' to console

DATSNR 	= $2222   ; 'SN err' entry for Input STMT
SNERR 	= $2228   ; entry for '?SN ERROR'
ULERR 	= $29CA   ; entry for '?UL ERROR'



# JP table for statements = $1AD1


# TOKEN table position = $1C1D, word list in 'extended BASIC' mode.
#	Token range: 88

# -- STATEMENTS --

#	USING		[229]	- $5CD1
#	TAB(		[220]	- $2C53
#	SPC(		[224]	- same as TAB(
#	= assignment		[240]	
#	+ operand		[242]	- $304E
#	- operand		[243]	- $30F7
#	" string		[34]	- $627E
#	NOT		[225]	- $31FA
#	& specifier		[38]	- $3124
#	ERR		[227]	- $3083
#	ERL		[226]	- $3093
#	VARPTR		[232]	- $30A3
#	USR		[234]	- $12B6
#	INSTR		[222]	- $327C
#	TOKEN_?		[230]	- $6565
#	TOKEN_?		[233]	- $5964
#	TOKEN_?		[228]	- $64A2
#	TOKEN_?		[133]	- $5310
#	TOKEN_?		[223]	- $32F1

#	ELSE		[162]

#	AUTO      	[171]	- $2B15
#	AND      	[247]
#	ABS      	[6]	- $3C57
#	ATN      	[14]	- $4C61
#	ASC      	[21]	- $6484
#	CLOSE      	[195]	- $859A
#	CONT      	[154]	- $602D
#	CLEAR      	[146]	- $60D8
#	CINT      	[28]	- $3D61
#	CSNG      	[29]	- $3DD7
#	CDBL      	[30]	- $3E03
#	CVI      	[43]	- $5099
#	CVS      	[44]	- $509C
#	CVD      	[45]	- $509F
#	COS      	[12]	- $4BA9
#	CHR$      	[22]	- $6494
#	CALL      	[182]	- $5410
#	COMMON      	[184]	- $8585
#	CHAIN      	[185]	- $8588
#	CSAVE      	[155]	- $1593
#	CLOAD      	[156]	- $1714
#	CLS      	[160]	- $0F14
#	COLOR      	[167]	- $0F19
#	CRUN      	[207]	- $1958
#	COPY      	[210]	- $1AC7
#	DELETE      	[170]	- $36FD
#	DATA      	[132]	- $29EA
#	DIM      	[134]	- $59B2
#	DEFSTR      	[173]	- $28D0
#	DEFINT      	[174]	- $28D3
#	DEFSNG      	[175]	- $28D6
#	DEFDBL      	[176]	- $28D9
#	DEF      	[152]	- $32CA
#	DRAW      	[212]	- $12BE
#	ELSE      	[162]	- $29EC
#	END      	[129]	- $5FD8
#	ERASE      	[166]	- $6091
#	ERROR      	[168]	- $2B0A
#	ERL      	[226]
#	ERR      	[227]
#	EXP      	[11]	- $4A66
#	EOF      	[47]	- $85BB
#	EQV      	[250]
#	FOR      	[130]	- $26D3
#	FIELD      	[192]	- $8591
#	FILES      	[198]	- $85A3
#	FN      	[223]
#	FRE      	[15]	- $6682
#	FIX      	[31]	- $3E4F
#	GOTO      	[137]	- $2994
#	GO TO      	[137]	- $2994
#	GOSUB      	[141]	- $297D
#	GET      	[193]	- $8594
#	GR      	[190]	- $10B5
#	HEX$      	[26]	- $6247
#	INPUT      	[133]	- $2D4A
#	IF      	[139]	- $2B47
#	INSTR      	[230]
#	INT      	[5]	- $3E62
#	INP      	[16]	- $3489
#	IMP      	[251]
#	INKEY$      	[233]
#	JOY      	[32]	- $1A7E
#	KILL      	[200]	- $85A9
#	KEY      	[205]	- $0FE2
#	LPRINT      	[158]	- $2B85
#	LLIST      	[159]	- $3519
#	LPOS      	[27]	- $326D
#	LET      	[136]	- $2A11
#	LINE      	[177]	- $2CDE
#	LOAD      	[196]	- $859D
#	LSET      	[201]	- $85AC
#	LIST      	[147]	- $351E
#	LOG      	[10]	- $3AC0
#	LOC      	[48]	- $85BE
#	LEN      	[18]	- $6478
#	LEFT$      	[1]	- $64E4
#	LOF      	[49]	- $85C1
#	MERGE      	[197]	- $85A0
#	MOD      	[252]
#	MKI$      	[50]	- $5080
#	MKS$      	[51]	- $5083
#	MKD$      	[52]	- $5086
#	MID$      	[3]	- $651D
#	MOTOR      	[209]	- $0F57
#	MOVE      	[211]	- $12BB
#	MON      	[214]	- $6B96
#	NEXT      	[131]	- $615C
#	NULL      	[150]	- $6041
#	NAME      	[199]	- $85A6
#	NEW      	[148]	- $5EF9
#	NOT      	[225]
#	OPEN      	[191]	- $858E
#	OUT      	[157]	- $3495
#	ON      	[149]	- $2A77
#	OR      	[248]
#	OCT$      	[25]	- $6242
#	OPTION      	[186]	- $38A8
#	PRINT      	[145]	- $2B8D
#	PUT      	[194]	- $8597
#	POKE      	[153]	- $373F
#	POS      	[17]	- $3272
#	PEEK      	[23]	- $3735
#	POINT      	[234]
#	PAINT      	[213]	- $85B8
#	RETURN      	[142]	- $29CF
#	READ      	[135]	- $2E1A
#	RUN      	[138]	- $2966
#	RESTORE      	[140]	- $5FBA
#	REM      	[143]	- $29EC
#	RESUME      	[169]	- $2AC0
#	RSET      	[202]	- $85AF
#	RIGHT$      	[2]	- $6514
#	RND      	[8]	- $4B14
#	RENUM      	[172]	- $3778
#	RESET      	[204]	- $85B5
#	RANDOMIZE      	[187]	- $38F2
#	RES      	[179]	- $12C1
#	STOP      	[144]	- $5FD4
#	SWAP      	[165]	- $6050
#	SAVE      	[203]	- $85B2
#	SPC(      	[224]
#	STEP      	[221]
#	SGN      	[4]	- $3C6C
#	SQR      	[7]	- $49FE
#	SIN      	[9]	- $4BAF
#	STR$      	[19]	- $624C
#	STRING$      	[228]
#	SPACE$      	[24]	- $64CB
#	SYSTEM      	[189]	- $858B
#	SET      	[178]	- $12C4
#	SOUND      	[206]	- $1198
#	THEN      	[219]
#	TRON      	[163]	- $604A
#	TROFF      	[164]	- $604B
#	TAB(      	[220]
#	TO      	[218]
#	TAN      	[13]	- $4C4C
#	TEXT      	[188]	- $0F8A
#	USING      	[229]
#	USR      	[222]
#	VAL      	[20]	- $653E
#	VARPTR      	[232]
#	VERIFY      	[208]	- $1962
#	WIDTH      	[161]	- $34BC
#	WAIT      	[151]	- $349C
#	WHILE      	[180]	- $5380
#	WEND      	[181]	- $53A1
#	WRITE      	[183]	- $54D3
#	XOR      	[249]
#	Z
#	[+      	[242]
#	[-      	[243]
#	[*      	[244]
#	[/      	[245]
#	[^      	[246]
#	[\      	[253]
#	['      	[231]
#	[>      	[239]
#	[=      	[240]
#	[<      	[241]
#
 
Link to comment
Share on other sites

Hi Nippur72, et al.

 

 

do you already know about "basck" ? it's tool in the Z88DK compiler that automatically scans a ROM dump and finds MS basic entry points:

 

 

I was aware of it, but hadn't though to try it.

Your list shows it does a pretty good job of locating most things.

 

----

 

Can I trouble you to test a couple of things on your real machine?

 

I'm looking at Bits #6 and #7 of &H6800 on write.

 

Bit#7 should be the cassette motor control output.

 

Bit#6 is turned on/off by a routine which hangs off the interrupt chain if a certain key combination is pressed: SHIFT-CONTROL-1 (I think)

 

I'm wondering if Bit#6 controls the "GT" output of the gate array, which is connected to the character generator?

If so, it may switch visible character sets on machines which have CGA11 and CGA12 correctly jumpered?

 

Cheers,

Leslie

 

 

RAM:0A56 sub_A56: ; CODE XREF: RAM:0A1A↑p
RAM:0A56
RAM:0A56 ; FUNCTION CHUNK AT RAM:0AD3 SIZE 0000000B BYTES
RAM:0A56
RAM:0A56 06 02 ld b, 2 ; Bring in I/O Bank
RAM:0A58 CD E5 0A call SET_BANK1_B ; set Bank#1 to value in B reg, save old on stack, and return
RAM:0A5B 21 FF 6A ld hl, 6AFFh ; Keyboard row 'C'?
RAM:0A5E CB 76 bit 6, (hl) ; check CAPS LOCK ?
RAM:0A60 28 11 jr z, loc_A73
RAM:0A62 CD A3 0A call CHECK_CONTROL_KEY ; check if control key is down - ZERO if true
RAM:0A65 20 2F jr nz, loc_A96
RAM:0A67 21 F7 6F ld hl, 6FF7h ; check Row KA3
RAM:0A6A CB 6E bit 5, (hl) ; bit 5 = '1' key?
RAM:0A6C 20 28 jr nz, loc_A96
RAM:0A6E 3E 3F ld a, 3Fh ; '?'
RAM:0A70 32 F0 85 ld (byte_85F0), a
RAM:0A73
RAM:0A73 loc_A73: ; CODE XREF: sub_A56+A↑j
RAM:0A73 21 FB 85 ld hl, operation_flags2
RAM:0A76 CB 6E bit 5, (hl)
RAM:0A78 20 21 jr nz, loc_A9B
RAM:0A7A CB EE set 5, (hl)
RAM:0A7C 3A F9 85 ld a, (REG_6800W) ; Saved copy of $6800 I/O Write byte
RAM:0A7F CB 77 bit 6, a
RAM:0A81 20 0D jr nz, loc_A90
RAM:0A83 CB F7 set 6, a ; what does Bit #6 in $6800 do in write mode
RAM:0A85 CB 9E res 3, (hl)
RAM:0A87
RAM:0A87 loc_A87: ; CODE XREF: sub_A56+3E↓j
RAM:0A87 32 00 68 ld (loc_67FF+1), a
RAM:0A8A 32 F9 85 ld (REG_6800W), a ; Saved copy of $6800 I/O Write byte
RAM:0A8D C3 D3 0A jp RESTORE_BNK1 ; Restore Bank#1 from values on the stack
RAM:0A90 ; ---------------------------------------------------------------------------
RAM:0A90
RAM:0A90 loc_A90: ; CODE XREF: sub_A56+2B↑j
RAM:0A90 CB B7 res 6, a
RAM:0A92 CB DE set 3, (hl)
RAM:0A94 18 F1 jr loc_A87
Link to comment
Share on other sites

I tried to flip bit 6 and bit 7 of &H6800 (with bank 1 switched to 2), but nothing happens. I tried that in 40 and 80 columns. Nothing.

I also tried CTRL+SHIFT+key on all keys, but it behaved normally.

MON
9000Z
DI
LD A, 02
OUT (41), A
LD A, C0
LD (6800), A
LD A, 01
OUT (41), A
EI
RET

If you have any other test you want me to run, just ask.

Link to comment
Share on other sites

Leslie, I think you've found something :)

not satisfied by yesterday's test, I debugged the unidentified bits in the emulator looking for how and when they were changed.

 

Bit 7 and 4 still remain untouched everywhere; but bit 6 it's the CAPS LOCK state (CAPLK in the schematics).

 

CAPLK is also triggered by CTRL+1 as you've found in your disasselmby. The reason? Laser 350 does not have a dedicated caps lock key, so they made it available via this key combination.

 

Somewhere in the keyboard routine there also should be the code that checks the actual caps lock key and flips the bit.

 

This is the code I used for debbuging in the emulator, you can try it yourself: open the JavaScript console (F12) and paste this:

(function() {
   let old_io_bit_7, old_caps_lock_bit, old_io_bit_4;
   debugBefore = ()=> {      
      old_io_bit_7      = io_bit_7;
      old_caps_lock_bit = caps_lock_bit;
      old_io_bit_4      = io_bit_4;
   }
   debugAfter = ()=> {                
      let { pc } = cpu.getState();
      if(old_io_bit_7 != io_bit_7)           console.log(`bit 7 changed from ${old_io_bit_7     } to ${io_bit_7     } at ${hex(pc,4)}`);
      if(old_caps_lock_bit != caps_lock_bit) console.log(`bit 6 changed from ${old_caps_lock_bit} to ${caps_lock_bit} at ${hex(pc,4)}`);
      if(old_io_bit_4 != io_bit_4)           console.log(`bit 4 changed from ${old_io_bit_4     } to ${io_bit_4     } at ${hex(pc,4)}`);
   }
})();
Link to comment
Share on other sites

Hi Nippur72,

 

 

Leslie, I think you've found something :)

not satisfied by yesterday's test, I debugged the unidentified bits in the emulator looking for how and when they were changed.

 

Bit 7 and 4 still remain untouched everywhere; but bit 6 it's the CAPS LOCK state (CAPLK in the schematics).

 

 

Thanks for the debug code!

 

That explains the code for the CTRL-1 == capslock!

 

-----

 

I tried your debug code out with the "MOTOR ON" and "MOTOR OFF" commands from BASIC.

 

They are definitely flipping bit#7 in &H6800 writes.

 

"MOTOR ON" gives:

 

bit 7 changed from 0 to 1 at 0f7c
"MOTOR OFF" gives:
bit 7 changed from 1 to 0 at 0f7c

 

If you have a cassette recorder attached with the correct remote cable attached and the play and/or record buttons down,

it should start and stop the recorder.

 

Cheers,

Leslie

Link to comment
Share on other sites

Hi Platis,

 

 

Can't say that I have seen that one.

Doesn't appear to be on any of the popular VZ200-300/LASER 310 repositories that I can see.

 

No use for programming the Laser 350/500/700 models of course.

 

Cheers,

Leslie

Link to comment
Share on other sites

  • 2 months later...

Hi, I need some help... I'm going to make a FPGA implementation of the Laser 500 and need to understand better the matter about the clock. Or I should say clocks, because looking at the schematics there are two of them. The first is 17.73447 Mhz which should be the standard PAL reference for generating the colour burst signal.

The other is a 14.77873 Mhz, which divided by 4 should provide the 3.6947 Mhz CPU clock.

I have included the schematic in the picture below. Both clocks go directly into the big VLSI chip (F17M and F14M pins). From my little understanding F14M is not the actual 14 MHz signal, but it is divided by 4 via the flip flops.

What I don't understand is:

1) why there are two clocks at all? Knowing that at VTECH they were cost-reducing oriented, why didn't they derive the CPU clock by dividing the video by 5? (resulting in a 3.546894 Mhz signal).

2) how they cope with the fact that the pixel-clock (for generating the video) and CPU clock are not multiples and thus not aligned? (e.g. when accessing RAM).

3) looking at the 74LS273 in the schematic (the one with the 7 flip-flops) I don't get how the divide by 4 is achieved... shouldn't it be just two flip flops?

4) most important question: why on earth the CPU clock divider takes as input the HSYNC signal?? From what I know, HSYNC is a signal that is always "1" except for a brief period at the start of every scanline. Doesn't this mean that the CPU stops for a little at every scan line?

post-31739-0-13331000-1556267187_thumb.jpg

Link to comment
Share on other sites

Hi Nippur72, et al.

 

1. Not sure.

 

2. CPU Clock and Mem accesses are synchronised to the F14M signal. (pg 214 of the tech manual, posted in this thread)

 

3. The flip-flops provide a digital delay, not a divide by 4 . Pin 9 of the LS02 takes a product of the delay circuit.

When pin 9 is low, F14M runs freely same as T14M, but inverted.

When pin 9 is high, F14M is held low.

 

When HSYNC goes from High to low, the circuit holds F14M low for 6 (or 7) 14Mhz clocks.

When HSYNC goes from low to high, there is no delay.

 

4. Maybe the GA1 uses this time to reload the colour registers etc. in preparation for the next display line?

 

Cheers,

Leslie

Link to comment
Share on other sites

Leslie, thanks for the detailed explanation!

It's still obscure why the CPU has to be put on hold during HSYNC, as there should be plenty of time to load registers for the new line (the beam is still in the invisible area of the CRT).

 

My guess is that it's a fix to problem that arose after the production of the big VLSI chip, otherwise the delay line and the other gates would have been included directly into the chip, right?

So there are 7 clock cycles skipped on every scanline, for a total of 7 x 312 = 2184 cycles. This means a 2184 : 4 = 546 Hz slowdown for the CPU.

 

Unfortunately that is only a small part of the difference between the nominal CPU frequency (3.6947 Mhz) and what I have deduced experimentally from my tests (~3.6702 Mhz). There is a ~25000 Hz difference lost somewhere else within the chip (that number is after taking into account the wait states for memory access).

It might be that the missing cycles are for something that is scaline-based, like the above HSYNC. If this is the case, it would be ~25000 Hz / 312 lines = ~80 cycles lost at each scanline. And since the screen/graphic is 80-column based, it might be that the CPU is put on hold for 1 cycle at every grid column (for loading the bitmap etc...).

What do you think? Is that reasonable? If so, I could finally fix my emulator!



 

 

 

Link to comment
Share on other sites

Hi Nippur72,

 

It's still obscure why the CPU has to be put on hold during HSYNC, as there should be plenty of time to load registers for the new line (the beam is still in the invisible area of the CRT).

My guess is that it's a fix to problem that arose after the production of the big VLSI chip, otherwise the delay line and the other gates would have been included directly into the chip, right?

So there are 7 clock cycles skipped on every scanline, for a total of 7 x 312 = 2184 cycles. This means a 2184 : 4 = 546 Hz slowdown for the CPU.

 

Unfortunately that is only a small part of the difference between the nominal CPU frequency (3.6947 Mhz) and what I have deduced experimentally from my tests (~3.6702 Mhz). There is a ~25000 Hz difference lost somewhere else within the chip (that number is after taking into account the wait states for memory access).

It might be that the missing cycles are for something that is scaline-based, like the above HSYNC. If this is the case, it would be ~25000 Hz / 312 lines = ~80 cycles lost at each scanline. And since the screen/graphic is 80-column based, it might be that the CPU is put on hold for 1 cycle at every grid column (for loading the bitmap etc...).

What do you think? Is that reasonable? If so, I could finally fix my emulator!

 

I thought about the problem some more..

 

It's possible that stopping the F14M clock in that position has something to do with the colour burst signal generation.

Your suggestion that it may be an add-on circuit to fix a bug in the VLSI chip that was only discovered after they were produced may not be a bad guess either.

 

I don't think that the missing cycles have anything to do with scanline dependent features.

 

According to the timing diagram, there is a one cpu clock wait state inserted for *every* memory access, whether it be read/write/opcode fetch.

 

Are you accounting for the instructions and overhead during the interrupt after each vertical retrace?

 

 

Regards,

Leslie

 

P.S. I think it is an interesting co-incidence that the Laser 350/500/700 series employs the same control register address ($6800) as the earlier LASER 310/VZ200/VZ300 machines.

 

The graphics/text screen layouts on the 350/500/700 are basically the same as an Apple ][.

It would come as no surprise to learn that VTECH used some of the same VLSI code from their LASER 3000 series machine here.

 

I had a quick look at the Laser 3000 tech manual, but it does not have a delay line circuit like the 350-700.

Link to comment
Share on other sites

I am already accounting for the memory access done by the CPU; I count +1 for every memory/io accesses made by the last instruction (my emulator works at instruction level). This gets very close but still faster than it should be.

I am not good at reading the clock diagram, does it mean that the wait state is also insert when the VDC accesses the memory, not just the CPU? If so, I am not accounting that, because I don't know how and when the VDC reads the memory (but ok, we can guess it).

If this is the case, it would be 80 bytes read on every line (border excluded). I think no matter what graphic mode is on, they are always 80 bytes (e.g. in TEXT 40: 40 characters + 40 colors, etc).

so: 3694700 - 192*80 - 312*(7/4) (for HSYNC) = 3678794

This is still a bit faster, it should be something around 3672000.

Could it be that the HYSC wait is triggered for the whole HSYNC period, not just on the positive edge of it? For numbers to match it needs to be around 22 cycles of F14M.


Regarding the copy from Apple, eh eh yes VTech was not new to it :-) The whole FD-100 disk drive is a clone, and also they had the Laser 128 which was a whole computer cloned!
Link to comment
Share on other sites

 

I am already accounting for the memory access done by the CPU; I count +1 for every memory/io accesses made by the last instruction (my emulator works at instruction level). This gets very close but still faster than it should be.

 

I am not good at reading the clock diagram, does it mean that the wait state is also insert when the VDC accesses the memory, not just the CPU? If so, I am not accounting that, because I don't know how and when the VDC reads the memory (but ok, we can guess it).

 

If this is the case, it would be 80 bytes read on every line (border excluded). I think no matter what graphic mode is on, they are always 80 bytes (e.g. in TEXT 40: 40 characters + 40 colors, etc).

 

so: 3694700 - 192*80 - 312*(7/4) (for HSYNC) = 3678794

 

This is still a bit faster, it should be something around 3672000.

 

Could it be that the HYSC wait is triggered for the whole HSYNC period, not just on the positive edge of it? For numbers to match it needs to be around 22 cycles of F14M.

Regarding the copy from Apple, eh eh yes VTech was not new to it :-) The whole FD-100 disk drive is a clone, and also they had the Laser 128 which was a whole computer cloned!

 

 

According to the timing diagram, the CPU and VIDEO sub-section share access to the RAM memory on each alternate CPU clock cycle. A 1:1 basis.

 

Third line of the diagram shows the CPU CK (CPU CLOCK).

 

CPU doesn't know anything about the video section, so it can issue a memory read/write instruction fetch at *any* time, during the CPU "slot" or VIDEO "slot".

 

You will need to take a look at a Z80 tech manual to see that each memory read/write operation takes 3 clock cycles ("T" states) and an instruction fetch takes 4.

(Assuming no wait states).

 

On a mem read/write cycle, *MREQ , *RD both go low on the falling edge of the T1 state.

*WR goes low on the falling edge of the T2 state.

 

Referring back to the Laser timing diagram, this will always be when CPU CK is LOW.

 

There is no way of knowing if that falls in the CPU allocated slot, or the video slot.

 

VIDEO always reads a byte in one "slot"

CPU always requires two "slots".

 

Consider for a minute that the CPU clock is 3.6947 Mhz.

That means that the period of the CPU clock is somewhere close to 271ns.

Plenty of time for the VIDEO section to read a byte from RAM in it's "slot".

 

The point where the CPU asserts *RD or *WR in the cycle (3/4 of the way through the "slot") doesn't allow enough time for the RAMS to respond however.

 

A one-cpu-clock wait state is therefore always inserted for every memory byte read, memory byte write and for each byte of the instruction fetch

(including one wait state for each operand byte) regardless of which "slot" the CPU read/write is initiated in.

 

I don't think that I/O instructions have a wait state inserted according to the diagram.

 

---

 

Regarding the HSYNC.

 

No, it's only triggered on the falling edge... according the the diagram.

 

 

Cheers,

Leslie

 

 

Edited by RedskullDC
Link to comment
Share on other sites

Leslie, thanks for the explanation! Got it, but still it seems we don't have all the information needed to find out the missing CPU cycles...

Perhaps it's better to focus on the VDC timings first, if we get it right then we can use the raster or some other trick to deduce the other timings.

I assume the pixel clock is F14M (14778730) as any sub-multiple of it isn't able of displaying 640 pixel horizontally. I also assume the VDC renders 312 scanlines as it is commonly done (not certain but it's in line with some of my tests). Another assumption is that there are no clock cycles spent between two frames (this is also common).

I have measured a refresh rate of ~49.7 Hz using the interrupt, this gives me the following formula:

14778730 / 312 / 49.7 = 953.07 pixels per line. When rounded, 953 gives back a refresh rate of 49.7038 Hz.

The value of 953 pixels includes HSYNC, front and back porch, left and right borders and active area. All of these are unknown, except the active area which is of course 640 pixels. The unknown values be guessed by making them close to a standard PAL signal:

HSYNC = 4.7us = 70 pixels
blank = 5.65us = 84 pixels
visible area = 52us = 780 pixels (70 + 640 + 70)
front porch = 1.65us = 21 pixels

A way these numbers can be tested is to generate a PAL signal out of it and see if the active area size matches the one of a real Laser 500. It could be the first step in my FPGA implementation.

Any other idea?

Link to comment
Share on other sites

They look like sane values to produce a PAL signal.

 

I don't think there is any way to figure out the missing CPU signals without putting a logic analyser on a real machine.

 

To assist with that , I just purchased a Laser 500 which I saw on Ebay: https://www.ebay.com.au/itm/202660668891 :-D

 

--

 

I wouldn't be too concerned with emulating the PAL output and memory wait states in an FPGA version. It really isn't necessary

 

Much easier to use dual port memory for the video memory regions, and let the video and cpu run completely independently.

 

If the machine is running a bit fast, can always lower the CPU clock.

 

Disk system runs independently off its' own 4MHz clock, so no need to sync that.

 

17MHz signal is not required at all on the FPGA.

 

If you want to use the entire screen, recommend using 1280x960 as the video output standard (4:3)

On the max resolution screen (640 x 192) each horizontal pixel is displayed twice, and each vertical line is displayed 5 times. 640 x 2 = 1280, 192 * 5 = 960.

 

Otherwise, SVGA=800x600. Multiply the vertical lines by 3 = 576.

 

Centre the video, and display the border register colour when outside the 640x192 area.

 

Cheers,

Leslie

Link to comment
Share on other sites

good about the Laser 500 purchase, they are quite rare nowdays! Does it have the manual too? (BTW, I forgot to tell that a friend is already scanning the english one, we'll have it in the coming weeks).

As for the FPGA implementation, the fun is to implement the machine as close as possible to the original, that's my target :-)

My board (the "MiST") has a composite output so it's born to produce a PAL or NTSC signal directly, which is cool if you still own an old CRT TV/Monitor. Another Laser 500 owner is going to measure the composite signal with an oscilloscope. It will be interesting to know how many lines are actually rendered (if they are not 312 then all the calculations are incorrect).

For a VGA output, 800x600 is a good suggestion because it's able to show a little of the borders, but I'm not sure I can generate a standard 800x600 VGA signal out of the F14M signal (or multiples). In case I'll use a frame buffer and make it independent as you suggested.

  • Like 1
Link to comment
Share on other sites

I'm hacking my JavaScript emulator to make it simulate an FPGA, it's a lot easier to catch bugs than working on the FPGA directly. The CPU has increased drastically but still under 100%. It's incredible how JavaScript can emulate a chip running at 14 MHz !

Here is the simulated video signal that it's generating... notice the HSYNC, front and back porch and the VSYNC. The active area is still messy.

 

post-31739-0-22274100-1556647155_thumb.png

Link to comment
Share on other sites

good about the Laser 500 purchase, they are quite rare nowdays! Does it have the manual too? (BTW, I forgot to tell that a friend is already scanning the english one, we'll have it in the coming weeks).

 

As for the FPGA implementation, the fun is to implement the machine as close as possible to the original, that's my target :-)

 

My board (the "MiST") has a composite output so it's born to produce a PAL or NTSC signal directly, which is cool if you still own an old CRT TV/Monitor. Another Laser 500 owner is going to measure the composite signal with an oscilloscope. It will be interesting to know how many lines are actually rendered (if they are not 312 then all the calculations are incorrect).

 

 

 

I don't think the one I purchased came with any manuals :(

The auction pics show it to be a QWERTY model keyboard, with only ENGLISH keytops.

Will be interesting to see if the ROMS are the same as what we already have.

 

 

Definitely looking forward to a scanned copy of the BASIC manual and tech manual.

They would clear up a lot of mysteries I'm sure!

 

----

 

Easiest way to implement the wait states on the 500 is to just have a circuit which inserts a one-cpu-clock wait state for every memory read/write/instruction fetch.

There isn't any need to tie it to the video generation to achieve the same effect as a real machine.

 

Better to have the video run independently, then you can have any output frequency you like. Doesn't need to be tied to the 14.7MHz clock.

 

The digital delay line circuit introduces a ~ 473ns (1000ns/ 14.7MHz * 7 = 473ns) pause in the 14Mhz clock after every *HSYNC.

If you are planning to use the same Z80 core as the LASER_310_FPGA project, it already has a clock enable input which you could use to mimic this delay.

 

Re-creating the hardware as close as possible is a great idea. Don't think I'm trying to point you in a different direction. :)

At some point (if you are like me) you will most likely want to extend the FPGA implementation to :

a) run faster

b) emulate disks/cassettes

c) more memory

d) extended screenmodes (such as the Laser 3000 HI-RES RGB modes)

 

With that in mind, it is best not to cripple your video output section to mimic hardware kludges from the 1980's if you don't have to ;-)

 

Look forward to seeing your progress!

 

Cheers,

Leslie

Edited by RedskullDC
Link to comment
Share on other sites

The ENGLISH keytops is also the ones I have (two of them). Messages back in this thread we found the ROM contains the ENG,GER,FRA charset which are selected by a switch on the board, so it's likely that the ROM is the same.

 

Regarding the HSYNC delay, there is one thing that is it not clear to me... the circuit delays F14M which feeds the VLSI chip that in turn generates the HSYNC signal. So the chip puts itself on hold? Is that correct?

 

I already have a working PAL signal that matches quite closely the original. And I am also coding the video generation, I wrote it first in a Verilog-like JavaScript and it's mostly working.

 

post-31739-0-76797000-1556754443.jpg

  • Like 1
Link to comment
Share on other sites

Regarding the HSYNC delay, there is one thing that is it not clear to me... the circuit delays F14M which feeds the VLSI chip that in turn generates the HSYNC signal. So the chip puts itself on hold? Is that correct?

 

 

 

That is correct, but it also gives us the answer to the reason for delay circuit!

 

Since the F14M clock is stopped, nothing is advancing in the VLSI.

 

The *only* effect that the delay circuit has is to stretch the HSYNC pulse by around 470ns

 

Presumably the HSYNC pulse coming out of the VLSI chip is too short due to an error in the logic which was only discovered after the VLSI chips were already manufactured?

 

Has the unfortunate side effect of slowing the CPU down by 470ns every horizontal line.

 

Cheers,

Leslie

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...