% 6.111 Final Project - Fall 1996 - "PIC-Cam" %
% Kenneth B. Russell <kbrussel@mit.edu> %

INCLUDE "lpm_counter.inc";
INCLUDE "pc_const.inc";

% Counter which implements required counting functions for the %
%    digitization process. %
% Specifications: %
%     1. 24-bit up counter (can count bytes): outputs are %
%        numbered 24..1 %
%     2. Counts column addresses (bits 13..3) modulo 160. %
%        That is, the lower 8 bits are reset each time they %
%        reach a value of 160 (actually count 0..159). % 
% How to translate into row and column addresses for DRAM: %
%     row_addr[11..1] = q[24..14] %
%     col_addr[11..1] = q[13..3] %
%     Low/high 16-bit word determined by q[2] %
%     Low/high byte of word determined by q[1]. %

% Notes: %
%   I attempted to add a "mode" switch to this counter to allow %
%   it to count both "modulo 160" and normally. However, this caused %
%   an unacceptable amount of logic bloat. Since we're not DRAM-limited, %
%   this "optimization" isn't, and it's more efficient to simply waste %
%   a little RAM. RAM's cheap. :-) %

SUBDESIGN digictr
(
	% Inputs %
	clock		: INPUT;
	cnt_en		: INPUT;  % Enable counting by bytes %
	cnt2_en		: INPUT;  % Enable counting by 16-bit words %
	cnt4_en		: INPUT;  % Enable counting by 32-bit words %
	aclr		: INPUT;  % Asynchronous clear %
	sload		: INPUT;  % Synchronous load %
	data[24..1]	: INPUT;  % Load data (NOTE this is required, unlike in lpm_counter) %

	% Following line is associated with the mode "optimization" %
	%mode		: INPUT;%  % GND = "normal" mode, VCC = "digitizing" mode (see above) %
	
	% Outputs %
	q[24..1]	: OUTPUT;
)
VARIABLE
	bytectr		: lpm_counter WITH (
		LPM_WIDTH = 1,
		LPM_DIRECTION = "UP"
	);
	shortctr	: lpm_counter WITH (
		LPM_WIDTH = 1,
		LPM_DIRECTION = "UP"
	);
	pixelctr	: lpm_counter WITH (
		LPM_WIDTH = 8,
		LPM_DIRECTION = "UP"
	);
	end_of_line		: NODE;
%	pixelctr_rco	: NODE; %
	reset_condition	: NODE;
	linectr		: lpm_counter WITH (
		LPM_WIDTH = 14,
		LPM_DIRECTION = "UP"
	);
BEGIN
	% Define end-of-line condition, when pixel counter is reset %
	% in "digitizing" mode %
	end_of_line = (pixelctr.q[] == PIXELS_PER_ROW - 1);

	reset_condition = end_of_line;

	% Define Ripple Carry Out condition for pixel counter, for %
	% "normal" counting mode %
%	pixelctr_rco = (pixelctr.q[] == B"11111111"); %

	% Reset condition is the logical OR of the above two expressions, %
	% conditionalized on the mode %
%	reset_condition = (((mode == VCC) & end_of_line) # ((mode == GND) & pixelctr_rco)); %
	
	% Assign counters' q nodes to the appropriate output ranges %
	q[1] = bytectr.q[];
	q[2] = shortctr.q[];
	q[10..3] = pixelctr.q[];
	q[24..11] = linectr.q[];
	
	% Hook up the clocks %
	bytectr.clock = clock;
	shortctr.clock = clock;
	pixelctr.clock = clock;
	linectr.clock = clock;
	
	% Hook up the clear inputs %
	bytectr.aclr = aclr;
	shortctr.aclr = aclr;
	pixelctr.aclr = aclr;
	linectr.aclr = aclr;
	% Following line clears pixel counter (SYNCHRONOUSLY) every time it reaches the %
	%    end of a line. This avoids logic glitches. %
	% This means it outputs 0..PIXELS_PER_ROW-1 and repeats. %
	pixelctr.sclr = (((cnt4_en == VCC) & reset_condition) #
					 ((cnt2_en == VCC) & reset_condition & (shortctr.q[] == H"1")) #
					 ((cnt_en == VCC) & reset_condition &
					  (shortctr.q[] == H"1") & (bytectr.q[] == H"1")));

	% Hook up the data input %
	bytectr.data[] = data[1];
	shortctr.data[] = data[2];
	pixelctr.data[] = data[10..3];
	linectr.data[] = data[24..11];
	
	% Hook up the load input %
	bytectr.sload = sload;
	shortctr.sload = sload;
	pixelctr.sload = sload;
	linectr.sload = sload;

	% Hook up the enable/RCO inputs. Tricky. Careful! %
	bytectr.cnt_en = cnt_en;
	shortctr.cnt_en = (((bytectr.q[] == H"1") & (cnt_en == VCC)) #
					   (cnt2_en == VCC));
	pixelctr.cnt_en = (((cnt_en == VCC) & (bytectr.q[] == H"1") & (shortctr.q[] == H"1")) #
					   ((cnt2_en == VCC) & (shortctr.q[] == H"1")) #
					   (cnt4_en == VCC));
	linectr.cnt_en = (((cnt4_en == VCC) & reset_condition) #
					  ((cnt2_en == VCC) & reset_condition & (shortctr.q[] == H"1")) #
					  ((cnt_en == VCC) & reset_condition &
					   (shortctr.q[] == H"1") & (bytectr.q[] == H"1")));
END;