; zaehler.asm 
;
; MCS4 (i4004) program to demonstrate some BCD arithmetic and controlling
; a multiplexed seven-segment display.
;
; We use register #0 of RAM #1 to manage an 8-digit BCD counter.
; The main loop of the program displays the counter value on an
; eight-digit multiplexed seven-segment display, where the segment-lines
; are driven by the output ports of two i4001 ROM chips,
; while the digit-lines are driven by one i4003 I/O expander.
;
; The circuit uses one i4004 CPU, three i4001 ROMs, one i4002 RAM,
; and one i4003 I/O expander.
;
; used CPU-registers:
; R0,R1   : tmp-register, indirect addressing
; R2,R3   : seven-segment decoding from R0 into R2/R3, see BCD2SEVEN
; R4,     : loop-counter in OUT4003
;    R5   : loop-counter in main program
; R6,R7   : index-register for RAM-register addressing
;
; (C) 2003, 2004, 2005 by
; Andreas Ruge and Norman Hendrich
; Univ. of Hamburg, Dept. CS
;


START
	JMS INIT_REG	; set initial counter value
	JMS FIRST_DIGIT ; and reset the digit index
	FIM R8R9 0x04	; RAM #1, Bank #0, Adresse 0
	JUN SHOW_REG_LOOP ; main loop


; FIXME:  the documentation is not clear about which register is sent
;         during cycle X2 and X3. Is it R8=X2, R9=X3 or vice-versa?
; FIXME:  do we need to encode the SRC register pairs as 0,1,2,3,4,5,6,7 
;         or as 0,2,4,6,8,10,12,14 in the assembly?
;
; Please let us know should our choices turn out wrong... this would then
; need to be fixed both in hades.models.mcs4.MCS4Assembler and the
; corresponding logic in hades.models.mcs4.i400[124].
;
INIT_REG
	FIM R8R9, 0x04	; select RAM #1, register #0, cell #0
	SRC R8R9
	LDM 1
	WRM		; RAM1[0,0] = 1

	INC R9
	SRC R8R9
	LDM 5
	WRM		; RAM1[0,1] = 1 

	INC R9
	SRC R8R9
	LDM 9
	WRM		; RAM1[0,2] = 7

	INC R9
	SRC R8R9
	LDM 9		
	WRM		; RAM1[0,3] = 9

	INC R9
	SRC R8R9
	LDM 9		
	WRM		; RAM1[0,4] = 9

	INC R9
	SRC R8R9
	LDM 9		
	WRM		; RAM1[0,5] = 9

	INC R9
	SRC R8R9
	LDM 9		
	WRM		; RAM1[0,6] = 9

	INC R9
	SRC R8R9
	LDM 3		
	WRM		; RAM1[0,7] = 3

	BBL 0x0		; return

	
	



SHOW_REG_LOOP:		; endless main loop that displays the curent counter
			; value (8 BCD digits) on the 8-digit seven-segment
			; display.

 	SRC R8R9	;
	RDM 		; load RAM data into the accu
	XCH R0		; and transfer into R0
	JMS BCD2SEVEN	; decode into seven-segment pattern
	JMS SEVEN2ROM	; and display the seven-segment pattern

	JMS BREAK	; generate RAM output pulse for debugging

	JMS WAIT	; wait some time while one display is enabled
	JMS WAIT	
	JMS WAIT
	JMS WAIT
	JMS BREAK	; more debugging pulses
	JMS BREAK	;

	JMS DISPLAY_OFF	; switch the segment-drivers off
	JMS NEXT_DIGIT	; enable next digit
	
	INC R9		; increment digit index register R9
	CLC		; clear carry
	LD R9		
	RAL	
	; ADD R9 ; FIXME: Resultat im Akku, nicht in R9 !!!!

	JCN C _DIGIT8	; R9>8? yes, restore R9=0
	JUN SHOW_REG_LOOP ; not yet, show next digit data on display

_DIGIT8
	CLB
	XCH R9		; reset R9

	JMS BCD_INCR_RAM; increment counter value
	JMS FIRST_DIGIT	; activate digit 0
	JUN SHOW_REG_LOOP ; next iteration


                        
BCD_INCR_RAM          	; increment the current counter value stored
			; at RAM register locations 0..7
	FIM RARB 0x04
	SRC RARB	; select RAM
	CLB
	STC
	ADM		; digit0 into the accu
	DAA		; decimal adjust
	WRM

	FIM RARB 0x14
	SRC RARB	; select RAM
	LDM 0x0	
	ADM		; digit1 into the accu
	DAA		; decimal adjust
	WRM

	FIM RARB 0x24
	SRC RARB	; select RAM
	LDM 0x0	
	ADM		; digit2 into the accu
	DAA		; decimal adjust
	WRM

	FIM RARB 0x34
	SRC RARB	; select RAM
	LDM 0x0	
	ADM		; digit3 into the accu
	DAA		; decimal adjust
	WRM

	FIM RARB 0x44
	SRC RARB	; select RAM
	LDM 0x0	
	ADM		; digit4 into the accu
	DAA		; decimal adjust
	WRM

	FIM RARB 0x54
	SRC RARB	; select RAM
	LDM 0x0	
	ADM		; digit5 into the accu
	DAA		; decimal adjust
	WRM

	FIM RARB 0x64
	SRC RARB	; select RAM
	LDM 0x0	
	ADM		; digit6 into the accu
	DAA		; decimal adjust
	WRM

	FIM RARB 0x74
	SRC RARB	; select RAM
	LDM 0x0	
	ADM		; digit7 into the accu
	DAA		; decimal adjust
	WRM

	BBL 0x0		; return


BREAK			; generate a short pulse on the output of ROM #2
			; for debugging purposes (allows us to use a
			; ValueTrigger or Counter to watch program execution).
			; 
	FIM R0R1 0x22	; 
	SRC R0R1	; select ROM #2
	LDM 0x4		
	WRR		; write 0100 to ROM output ports

	LDM 0x0		
	WRR		; write 0000 to ROM output ports
	BBL 0x0		; return




WAIT
	LDM 0xF		; wait loop counter = 15
_WLOOP	DAC		; decrement
	CLC		; clear carry (JCN NZ won't work without this?!)
	JCN NZ _WLOOP	; jump if not zero

	BBL 0x0		; return



FIRST_DIGIT 		; shift 0111 1111 11 into the digit-driver 4003
			; uses R4 as loop counter
			;
	LDM 0xA		; initialize R4=10
	XCH R4		; 
	FIM R0R1 0x22	; 
	SRC R0R1	; select ROM #2 

_OFFLOOP
	LDM 0x2		; 4003.data=1 4003.clock=0
	WRR
	LDM 0x3		; 4003.data=1 4003.clock=1
	WRR
	LD  R4		; decrement R4
	DAC
	XCH R4
	LD  R4
	JCN NZ _OFFLOOP ; next iteration


	LDM 0x0		; data=0, clock=0
	WRR
	LDM 0x1		; data=0, clock=1
	WRR
	LDM 0x0		; data=0, clock=0
	WRR

	BBL 0x0		; return


DISPLAY_OFF		; disable all eight segment outputs 
	FIM R0R1 0x00	;
	SRC R0R1	; select ROM #0
	LDM 0x0		;
	WRR		; segment outputs off (segments DCBA)
	FIM R0R1 0x11	;
	SRC R0R1	; select ROM #1
	LDM 0x0		;
	WRR		; segment outputs off (segments PGFE)
	BBL 0x0		; return


NEXT_DIGIT		; shift the active digit 
	FIM R0R1 0x22	;
	SRC R0R1	; select ROM #2
	LDM 0x2		; data=1, clock=0
	WRR		;
	LDM 0x3		; data=1, clock=1
	WRR		;
	LDM 0x2		; data=1, clock=0
	WRR		;
	BBL 0x0A	; return


	

BCD2SEVEN		; convert the BCD digit value of register 0 into 
			; a seven-segment code in registers R2/R3, where
			; R3 = PGFE and R2 = DCBA:
			;
			;    A
			;  F   B
			;    G
			;  E   C
			;    D   .DP
			;    
			; we use a data-table stored inside the program ROM
			; starting at address 0xF0 (see below).
			;
	LDM 0xF		; accu = 0xF
	XCH R1		; R1   = 0xF
	FIN R2R3	; fetch indirect from (R1,R0) = 0xF + bcd into (R3,R2)
	NOP		;
	BBL 0x0		; return



SEVEN2ROM		; transfer the 8-bit value from R2 and R3
			; to the output ports of the ROMs, with 
			; i4001=0 (R2, lower nibble) and 
			; i4001=1 (R3, upper nibble).
			; The ports drive the seven-segment display segments.
	FIM R0R1 0x00	; 
	SRC R0R1	; select ROM #0
	LD  R2		;
	WRR		; write R2 contents to the ROM ports

	FIM R0R1 0x11	;
	SRC R0R1	; select ROM #1
	LD  R3		;
	WRR		; write R3 contents to the ROM ports

	BBL 0x0		; return


	


	ORG 0xF0	; seven-segment decoder data table.
_SVTABLE
	DATA 0x3F	; "0" = __FE DCBA
	DATA 0x06	; "1" = ____ _CB_
	DATA 0x5B	; "2" = _G_E D_BA
	DATA 0x4F	; "3" = _G__ DCBA
	DATA 0x66	; "4" = _GF_ _CB_
	DATA 0x6D	; "5" = _GF_ DC_A
	DATA 0x7D	; "6" = _GFE DC_A
	DATA 0x07	; "7" = ____ _CBA

	DATA 0x7F	; "8" = _GFE DCBA
	DATA 0x6F	; "9" = _GF_ DCBA
	DATA 0x77	; "A" = _GFE _CBA
	DATA 0x7C	; "b" = _GFE DC__
	DATA 0x39	; "C" = __FE D__A
	DATA 0x5E	; "d" = _G_E DCB_
	DATA 0x79	; "E" = _GFE D__A
	DATA 0x40	; "-" = _G__ ____

	; end
