;	  This program is to control Cyrix's Cx486SLC/DLC internal cache.
;	  This program should be used for chip evaluation use only.
;	  If you want to use this program with '-e' option, be sure that
;	all required hardware modification had been done.
;	  This program could not run on the DOS running under MS-Windows,
;	for it accesses CR0 to cause previlage violation.
;	  For more information about Cx486SLC/DLC internal cache control,
;	see Cyrix's Cx486SLC/DLC data book and application note volume 1.
;
;	  Contents of makefile is shown below.
;
;	cx486cc.com : cx486cc.obj
;       	tlink /t /x cx486cc.obj
;
;	cx486cc.obj : cx486cc.asm
;       	tasm /m10 /z /zi /l cx486cc.asm
;
TRUE		equ	1
FALSE		equ	0
CR		equ	0dh
LF		equ	0ah
BEL		equ	07h
TAB		equ	09h
SPC		equ	20h
MSEOF		equ	1ah
I86		equ	00h
I186		equ	01h
I286		equ	02h
I386		equ	03h
I486		equ	04h
X486		equ	05h
V30		equ	06h
V33		equ	07h
BARB		equ	20h
NEC98		equ	FALSE
DEBUG		equ	FALSE
DUMPA		equ	FALSE
DISABLE_CACHE	macro
	mov	eax, cr0
	or	eax, 40000000h
	mov	cr0, eax
	INVD	;flash cache
	endm
ENABLE_CACHE	macro
	mov	ebx, cr0
	and	ebx, 9fffffffh
	mov	cr0, ebx
	endm
EXIT	macro
	mov	ah, 04ch
	mov	al, byte ptr cpu_type
	int	21h
	endm
;input	dx:offset to message
PUTSTR	macro
	mov	ah, 09h
	int	21h
	endm
;dx     --- offset to message
PUTS    macro   msg
        mov     ah, 09h
        mov     dx, offset msg
        int     21h
        endm
.486P
	CODE	SEGMENT USE16
	ASSUME	CS:CODE,DS:CODE
	ORG	0100H
start:
	db	"-Cx486CC-",MSEOF,'$'
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	cld
	call	check_cpu
	mov	byte ptr cpu_type, al
	call	disp_cpu
	mov	al, byte ptr cpu_type
	cmp	al, X486
	je	get_argc
	jmp	not_cyrix
get_argc:
	mov	si, 80h
	lodsb
	cmp	al, 0
	je	help
check_option:
	lodsb
	cmp	al,'/'				; option flag
	je	check_option_parameter
	cmp	al,'-'				; option flag
	je	check_option_parameter
	cmp	al, SPC
	je	check_option
	cmp	al, TAB
	je	check_option
	jmp	help
check_option_parameter:
	mov	al, byte ptr ds:[si]
	call	tolower
	cmp	al, 'f'
	je	enable_f
	cmp	al, 'e'
	je	enable
	cmp	al, 'd'
	je	disable
	cmp	al, 'v'
	je	dump
	jmp	help
not_cyrix:
	PUTS	helpmsg
	EXIT
help:
	PUTS	helpmsg
	PUTS	usage
	EXIT
enable_f:
	mov	ax, word ptr ccregs
	or	ah, BARB			;set BARB bit
	mov	word ptr ccregs, ax
enable:
	mov	cx, 14
	mov	si, offset ccregs
	mov	dx, 23h
	cli					;mask off external interrupts
	DISABLE_CACHE
enable_loop:
	lodsb
	out	22h, al
	outsb
	loop	enable_loop
	ENABLE_CACHE
	sti
	PUTS	enable_msg
	EXIT
disable:
	cli
	DISABLE_CACHE
	sti
	PUTS	disable_msg
	EXIT
dump:
	mov	di, offset work
	mov	si, offset ccregs
	call	get_ccr
	mov	si, offset work
	call	dmp_ccr
if	DEBUG
	cli
	mov	ebx, cr0
	sti
	call	dump_32
endif
	EXIT
;input si:buffer
dmp_ccr proc
if	DUMPA
	mov	di, offset ccrdmp
	mov	cx, 14
dump_loop:
	lodsb
	call	b2hexasc
	stosw
	loop	dump_loop
	PUTS	ccrdmpr
	PUTS    ccrdmp
else
	PUTS	ccr0_bit
	mov	bl, [si]
	inc	si
	push	si
	mov	cx, 8
	mov	si, offset ccr0_bit_table
ccr_loop0:
	mov	al, bl
	and	al, 01h
	add	al, '0'
	mov	dx, [si]
	mov	di, dx
	mov	byte ptr [di + 5], al
	PUTSTR
	inc	si
	inc	si
	shr	bl, 1
	loop	ccr_loop0
	pop	si
;ccr1
	PUTS	ccr1_bit
	lodsb
	and	al, 01h
	add	al, '0'
	mov	di, offset ccr1_bits
	mov	byte ptr [di + 5], al
	PUTS	ccr1_bits
	mov	cx, 4
ncr_reg_dmp_loop:
	push	cx
	PUTS	ccr_reg_dmp
	mov	cx, 3
	mov	di, offset ncr_address
ncr_reg_loop:
	lodsb
	call	b2hexasc
	stosw
	loop	ncr_reg_loop
	mov	byte ptr [di - 1], '0'
	PUTS	ncr_address
	dec	si
	xor	ax, ax
	lodsb
	and	al, 0fh
	push	si
	mov	si, offset size_table
	xor	ah, ah
	mov	bx, ax
	mov	al, [si + bx]
	add	ax, si
	mov	dx, ax
	PUTSTR
	PUTS	size_byte
	pop	si
	pop	cx
	inc	byte ptr ccr_reg_num
	loop	ncr_reg_dmp_loop
endif
	ret
ccrdmpr 	db	"c0c1c4c5c6c7c8c9cAcBcCcDcEcF",CR,LF,'$'
ccrdmp		db	"                            ",CR,LF,'$'
ccr_reg_dmp	db	"Non-cacheable region "
ccr_reg_num	db	"0 starting address :$"
ncr_address	db	"xxxxxx00  Size:$"
size_table	db	size0 - size_table, size1 - size_table
		db	size2 - size_table, size3 - size_table
		db	size4 - size_table, size5 - size_table
		db	size6 - size_table, size7 - size_table
		db	size8 - size_table, size9 - size_table
		db	sizeA - size_table, sizeB - size_table
		db	sizeC - size_table, sizeD - size_table
		db	sizeE - size_table, sizeF - size_table
size0		db	"0$"
size1		db	"4K$"
size2		db	"8K$"
size3		db	"16K$"
size4		db	"32K$"
size5		db	"64K$"
size6		db	"128K$"
size7		db	"256K$"
size8		db	"512K$"
size9		db	"1M$"
sizeA		db	"2M$"
sizeB		db	"4M$"
sizeC		db	"8M$"
sizeD		db	"16M$"
sizeE		db	"32M$"
sizeF		db	"4G$"
size_byte	db	"byte",CR,LF,'$'
ccr0_bit	db	"Cache Configuration Register 0 (C0h)",CR,LF,'$'
ccr1_bit	db	"Cache Configuration Register 1 (C1h)",CR,LF,'$'
ccr1_bits	db	"bit0= : RPL 1:enables RPLSET, /RPLVAL output "
		db	"pins",CR,LF
		db	"bit[1..7] reserved.",CR,LF,'$'
ccr0_bit_table	dw	ccr_bit0, ccr_bit1, ccr_bit2, ccr_bit3
		dw	ccr_bit4, ccr_bit5, ccr_bit6, ccr_bit7
ccr_bit0	db	"bit0= : NC0 1:sets the first 64KB at each 1MB "
		db	"boundary as non-cacheable",CR,LF,'$'
ccr_bit1	db	"bit1= : NC1 1:sets 640KB to 1MB region as "
		db	"non-cacheable",CR,LF,'$'
ccr_bit2	db	"bit2= : A20M 1:enables /A20M input pin",CR,LF,'$'
ccr_bit3	db	"bit3= : KEN 1:enables /KEN input pin",CR,LF,'$'
ccr_bit4	db	"bit4= : FLUSH 1:enables /FLUSH input pin",CR,LF,'$'
ccr_bit5	db	"bit5= : BARB 1:enables flushing of internal cache "
		db	"when hold state is entered",CR,LF,'$'
ccr_bit6	db	"bit6= : CO Selects cache organization. "
		db	"0:2 way set associative 1:direct mapped",CR,LF,'$'
ccr_bit7	db	"bit7= : SUSPEND 1:enables /SUSP input and "
		db	"/SUSPA output pins",CR,LF,'$'
	endp
;input di:buffer
get_ccr proc
	mov	dx, 23h
	mov	cx, 14
	cli
ccrread_loop:
	lodsw
	out	22h, al
	insb
	loop	ccrread_loop
	sti
	ret
	endp
if	DEBUG
;input	ebx
dump_32	proc
	cld
	mov	di, offset dump_buffer + 4
	mov	cx, 4
dump_32_loop:
	rol	ebx, 8
	mov	eax, ebx
	call	b2hexasc
	stosw
	loop	dump_32_loop
	PUTS	dump_buffer
	ret
dump_buffer	db 	"cr0:        h",CR,LF,'$'
	endp
endif
;input	al
;outpu	ax
b2hexasc	proc	near
	mov	ah, al
	shr	al, 4
	and	al, 0fh
	cmp	al, 09
	ja	b2hexasc_1
	add	al, 30h
	jmp	b2hexasc_2
b2hexasc_1:
	add	al, 37h
b2hexasc_2:
	and	ah, 0fh
	cmp	ah, 09
	ja	b2hexasc_3
	add	ah, 30h
	jmp	b2hexasc_4
b2hexasc_3:
	add	ah, 37h
b2hexasc_4:
	ret
	endp
tolower proc
        cmp al,'A'
        jb  exit_tolower
        cmp al,'Z'
        ja  exit_tolower
        add al,' '
exit_tolower:
	ret
	endp
check_cpu proc
test_8086:
	mov	cl, 33
	mov	al,  1
	shl	al, cl
	or	al, al
	jnz	test_186
test_v30:
	mov	ax, sp
	pusha		;pusha valid?
	nop
	nop
	nop
	nop
	nop
	cmp	ax, sp
	je	i8086
	popa
test_v33:
	mov	ax, 0100h
	aad	0h
	jz	nec_v33
	jmp	nec_v3020
test_186:
	pushf
	pop	ax
	test	ax, 08000h
	jnz	i80186
test_286:
	or	ax, 04000h
	push	ax
	popf
	pushf
	pop	ax
	test	ax, 04000h
	jz	i80286
test_386:
	pushfd
	pop	eax
	bts	eax, 18
	push	eax
	popfd
	pushfd
	pop	eax
	bt	eax, 18
	jnc	i80386
test_Cx486:
	mov	al, 08h
	add	al, 08h
	and	al, 00h
	daa
	cmp	al, 06h
	je	Cx486
;	jmp	i80486		;otherwise i486
i80486:
	mov	al, I486
	ret
i80386:
	mov	al, I386
	ret
i80286:
	mov	al, I286
	ret
i80186:
	mov	al, I186
	ret
i8086:
	mov	al, I86
	ret
nec_v3020:
	mov	al, V30
	ret
nec_v33:
	mov	al, V33
	ret
Cx486:
	mov	al, X486
	ret
	endp
;input	al:cpu type
;output	dx:offset to string
disp_cpu proc
	mov	si, offset cpu_table
	xor	ah, ah
	mov	bx, ax
	mov	al, [si + bx]
	add	ax, si
	mov	dx, ax
	PUTSTR
	PUTS	cpu_det
	ret
cpu_table	db	cpu86  - cpu_table
		db	cpu186 - cpu_table
		db	cpu286 - cpu_table
		db	cpu386 - cpu_table
		db	cpu486 - cpu_table
		db	cpx486 - cpu_table
		db	cpv30  - cpu_table
cpu86		db	"i8086$"
cpu186		db	"i186$"
cpu286		db	"i286$"
cpu386		db	"i386$"
cpu486		db	"i486$"
cpx486		db	"Cx486$"
cpv30		db	"V30$"
cpv33		db	"V33$"
cpu_det		db	" microprocessor detected.",CR,LF,'$'
	endp
cpu_type	db	0
work		db	"                $"
ccregs		dw	010c0h,000c1h
if	NEC98
		dw	000c4h,00ac5h,006c6h	;a0000-c0000, 128kb VRAM
		dw	000c7h,00cc8h,006c9h	;c0000-e0000, 128kb ROM/EMS
		dw	000cah,00ecbh,004cch	;e0000-e8000,  32kb VRAM
		dw	000cdh,00eceh,084cfh	;e8000-f0000,  32kb ROM/EMS
else
		dw	000c4h,00ac5h,006c6h	;a0000-c0000, 128kb Video
		dw	000c7h,00cc8h,004c9h	;c0000-c8000,  32kb
		dw	000cah,00ccbh,083cch	;c8000-cc000,  16kb
		dw	000cdh,00eceh,005cfh	;e0000-f0000,  64kb
endif
helpmsg 	db	"Cx486SLC/DLC cache control program ver. 1.51 for "
if	NEC98
		db	"NEC-98"
else
		db	"IBM-PC/AT"
endif
		db	" programed by HOS",CR,LF,'$'
usage		db	"Usage:Cx486CC -option",CR,LF
		db	"options: e:enable cache.",CR,LF
		db	"         f:enable cache.(flush on hold)",CR,LF
		db	"         d:disable cache.",CR,LF
		db	"         v:view internal cache control registers."
		db	CR,LF,'$'
disable_msg	db	"Internal cache disabled.",CR,LF,'$'
enable_msg	db	"Internal cache enabled.",CR,LF,'$'
CODE	ENDS
	END	START
;Technical note
;
;CCR0 (C0h)
;bit0 : NC0 1:sets the first 64KB at each 1MB boundary as non-cacheable
;bit1 : NC1 1:sets 640KB to 1MB region as non-cacheable
;bit2 : A20M 1:enables /A20M input pin
;bit3 : KEN 1:enables /KEN input pin
;bit4 : FLUSH 1:enables /FLUSH input pin
;bit5 : BARB 1:enables flushing of internal cache when hold state is entered
;bit6 : CO Selects cache organization. 0:2 way set associative 1:direct mapped
;bit7 : SUSPEND 1:enables /SUSP input and /SUSPA output pins
;
;CCR1 (C1h)
;bit0 : RPL 1:enables RPLSET, /RPLVAL output pins.
;bit1..7 : reserved.
;
;Size (bit[0..3] of c6,c9,cc,cf)
; 0:disabled    8:512KB
; 1:4KB         9:1MB
; 2:8KB         A:2MB
; 3:16KB        B:4MB
; 4:32KB        C:8MB
; 5:64KB        D:16MB
; 6:128KB       E:32MB
; 7:256KB       F:4GB