SX Microcontroller Memory Method DRAM Basics

; PROGRAM: Dynamic RAM Basics (DRAM.SRC)
;
; works with "RAS before CAS" DRAMs
;
; Written December 29, 1993
; Revised February 24, 1996
; Upon power up or reset, this program starts sampling pin ra.0 and 
; recording its state in sequential addresses of a 1Mb dynamic RAM. 
; When the DRAM is full, the program plays back the recorded bits
; in a continuous loop. 

	device	pins28,xt_osc,wdt_off,turbo,stackx,optionx
	reset	start

Sin	=	ra.0	; Signal generator input
RAS	=	ra.1	; DRAM row-address strobe
WR	=	ra.2	; DRAM write line (0 = write)
Dout	=	ra.3	; DRAM data line
CAS	=	rc.3	; DRAM column-address strobe
adrb_lo	=	rb	; Low bits of address bus
adrb_hi	=	rc	; High bits of address bus
Din	=	rc.2	; DRAM Q line
Sout	=	rc.5	; Signal out to speaker

        org     8       ; Start of available RAM

r_ctr	ds	1	; Refresh counter
row_lo	ds	1	; Eight LSBs of row address
row_hi	ds	1	; Two MSBs of row address
col_lo	ds	1	; Eight LSBs of column address
col_hi	ds	1	; Two MSBs of column address
flags	ds	1	; Holder for bit variable flag
flag	=	flags.0	; Overflow flag for 20-bit address

        org     0       ; Start of code space

start	setb	RAS	; Disable RAS and CAS before
	setb	CAS	; setting ports to output.
	mov	!ra,#1	; Make ra.0 (Sin) an input.
	mov	!rb,#0	; Make rb (low addresses) output. 
	mov	!rc,#00000100b	; Make rc.2 (Din) an input. 
	clr	flags	; Clear the variables. 
	clr	row_lo
	clr	row_hi
	clr	col_lo
	clr	col_hi
	call	refresh	; Initialize DRAM. 

:record	call	refresh	; Refresh the DRAM. 
	call	write	; Write Sin bit to DRAM. 
	call	inc_xy	; Increment row and col addresses.
	jnb	flag,:record	; Repeat until address overflows. 

:play	call	refresh	; Refresh the DRAM. 
	call	read	; Retrieve bit and write to Sout)
	call	inc_xy	; Increment row and col addresses.
	JMP	:play	; Loop until reset. 


write	mov	adrb_lo,row_lo	; Put LSBs of row addr onto bus (rb). 
	AND	adrb_hi,#11111100b	; Clear bits adrb_hi.0 and .1.
	OR	adrb_hi,row_hi	; Put MSBs of row addr onto bus (rc). 
	clrb	RAS	; Strobe in the row address. 
	movb	Dout,Sin	; Supply the input bit to the DRAM,
	movb	Sout,Sin	; and echo it to the speaker. 
	mov	adrb_lo,col_lo	; Put LSBs of col addr onto bus (rb). 
	AND	adrb_hi,#11111100b	; Clear bits adrb_hi.0 and .1.
	OR	adrb_hi,col_hi	; Put MSBs of col addr onto bus (rc). 
	clrb	WR	; Set up to write. 
	clrb	CAS	; Strobe in the column address.
	setb	WR	; Conclude the transaction by 
	setb	RAS	; restoring WR, RAS, and CAS high
	setb	CAS	; (inactive). 
	ret

read	mov	adrb_lo,row_lo	; Put LSBs of row addr onto bus (rb). 
	AND	adrb_hi,#11111100b	; Clear bits adrb_hi.0 and .1.
	OR	adrb_hi,row_hi	; Put MSBs of row addr onto bus (rc). 
	clrb	RAS	; Strobe in the row address. 
	mov	adrb_lo,col_lo	; Put LSBs of col addr onto bus (rb). 
	AND	adrb_hi,#11111100b	; Clear bits adrb_hi.0 and .1.
	OR	adrb_hi,col_hi	; Put MSBs of col addr onto bus (rc). 
	clrb	CAS	; Strobe in the column address.
	movb	Sout,Din	; Copy the DRAM data to the speaker. 
	setb	RAS	; Conclude the transaction by restoring 
	setb	CAS	; RAS and CAS high (inactive). 
	ret

; This routine implements a CAS-before-RAS refresh. The DRAM has an onboard
; counter to keep track of row addresses, so the status of the external 
; address bus doesn't matter. The DRAM requires 512 row addresses be refreshed
; each 8 ms, so this routine must be called once every 125 microseconds. 
; Changing the initial value moved into r_ctr will alter the refresh schedule. 
; For example, to refresh the entire DRAM, move #0 into r_ctr (256 loops) and 
; call the routine twice in a row (512). 

refresh	mov	r_ctr,#8
:loop	clrb	CAS	; Activate column strobe. 
	clrb	RAS	; Activate row strobe. 
	setb	CAS	; Deactivate column strobe. 
	setb	RAS	; Deactivate row strobe. 
	djnz	r_ctr,:loop	; Repeat. 
	ret

; This routine increments a 20-bit number representing the 1,048,576 addresses
; of the DRAM. For convenience, the number is broken into two 10-bit numbers, 
; which are each stored in a pair of byte variables. Note that wherever the 
; routine relies on the carry bit to indicate a byte overflow, it uses 
; the syntax "add variable,#1" not "inc variable." Inc does not set or clear 
; the carry flag. 

inc_xy	add	row_lo,#1	; Add 1 to eight LSBs of row addr. 
	sc		; If carry, add 1 to MSB, else return. 
	ret		
	inc	row_hi	; Increment MSBs of row address. 
	sb	row_hi.2	; If we've overflowed 10 bits, clear 
	ret		; row_ hi and add 1 to column 
	clr	row_hi	; address, else return. 
	add	col_lo,#1
	sc		; If carry, add 1 to MSB, else return. 
	ret
	inc	col_hi	; Increment MSBs of col address. 
	sb	col_hi.2	; If we've overflowed 10 bits, clear 
	ret		; col_ hi and set the flag to signal
	clr	col_hi	; main program that we've reached the 
	setb	flag	; end of available memory, then return. 
	ret