//
//						CPU16.v - 16-bit Central Processing Unit
//
//					  (C) Copyright 2007-2010 John B. Stephensen
//
// This Verilog source file and all its derivatives are licensed only for
// personal non-profit educational use in the Amateur Radio Service and
// the license is not transferrable. The information is provided as-is for
// experimental purposes and the author does not warranty its freedom
// from defects or its suitability for any specific application.
//
// This CPU is a RISC processor with 16 16-bit registers using 2-address instructions. It
// uses a Harvard architecture with a 16-bit instruction size and 16-bit data word lengths.
// Subsidiary modules decode ALU and program flow control instructions. Memory and I/O access are
// controlled from this module and the instruction formats are:
// 
//		 15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
//		+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//		| 1   0 | 1   1   0 |   Offset  |    Address    | Data Register | Write
//		+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// 	| 1   0 | 1   1   1 |        Port Number        | Data Register | OUT
//		+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//		| 1   1 | 0   0   0 |        Port Number        | Data Register | IN
//		+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//		| 1   1 | 0   0   1 |   Offset  |    Address    | Data Register | Read
//		+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
// Bits 15 and 14 encode the instruction type. A type 1 instruction carries immediate data in bits 11-4
// and specifies the register in bits 3-0. In type 2 and 3 instructions, bits 13-11 select a functional
// unit in the ALU to carry out a particular type of operation. Bits 10-8 specify the details of the
// operation performed by that functional unit. Bits 7-4 specify a source register or contain a constant
// value. Bits 3-0 specify the destination register which may also be a source. I/O instructions are an
// exception where bits 10-4 specify the I/O port being accessed. Memory instructions use the contents
// of register B as the address and add an offset from the instruction modifier field. Both use register
// A as the data source for writes and the data destination for reads. This module also determines the
// flags tested for conditional jumps as follows:
//
//		Flag	Condition
//		----	------------------------------
//		 00	Unconditional
//		 01	Overflow flag
//		 10	Carry flag
//		 11	Zero flag
//
// The zero flag is only modified by add and subtract operations. The carry flag is modified only by the
// bit test, shift, set carry, clear carry and 2-register add and subtract operations. All instructions
// execute in one clock cycle with the exception of the read and input instructions that require 2 cycles.
//
// Without multipler and divider: 101 MHz maximum and uses 244 slices (4% XC3S500E).
// With multipler and divider: 101 MHz maximum and uses 1 multiplier and 329 slices (6% XC3S500E).
// Speed limited by B input to adder/subtractor. Next slowest is MAC and condition code checking.
//
//	Normal warnings:
//		Signals <b<15:14>>, <prod<35:34>> and <prod<1:0>> are assigned but never used.
//
// History:
//		M001	5-31-08	Load immediate data to register.
//		M002	6-8-08	Remove encode instruction
//		M003	8-5-08	Convert to 16-bit instruction format
//		M004	9-29-08	Move input multiplexer to MCU16.v and bit test to ALU.v
//		M005	2-28-09	Use external memory with 2 cycle reads and do 2-cycle inputs
//		M006	3-24-09	Added mask instruction
//		M007	3-26-09	make program memory external to allow data access (remove PGM instruction)
//		M007	4-28-09	fix iord strobe bug
//		M008	7-13-09	changed link flag to overflow flag
//		M009	7-18-09	16-bit register load now 2 sequential 8-bit load instructions
//		M010	3-21-10	smaller divider
//		M011	3-25-10	allow pointer plus offset memory addressing
//
module CPU16(ioaddr, din, iord, dout, iowr,
				 maddr, min, mout, mwr,
				 paddr, pdata, pcs,
				 clk, rst);
	 output [6:0] ioaddr;		// I/O address bus (modifier field plus B addr. field)
    input [15:0] din;			// I/O data input
	 output iord;					// requesting data on input bus
    output [15:0] dout;			// I/O data output
    output iowr;					// valid data on output bus
	 output [13:0] maddr;		// memory address
	 input [15:0] min;			// memory data input
	 output [15:0] mout;			// memory data output
	 output mwr;					// memory write
	 output [13:0] paddr;		// program memory address
	 input [15:0] pdata;			// program data (instructions)
	 output pcs;					// program memory enable (used to hold instruction for additional cycle)
	 input clk;						// common clock
	 input rst;						// reset CPU state
// internal signals
wire [1:0] typ;					// instruction type
wire [2:0] op,mod;				// ALU operation and modifier
wire [15:0] a,b;					// register file outputs for address and data
wire zero,carry,ovflo;			// ALU flags
wire inp,out,write,read;		// I/O and memory operations
wire inrd1;							// I/O input or memory read cycle 1 and 2
reg inrd2;
// Program flow control logic reads instructions from ROM and controls branching.
// Branches occur if specific flags set - MSB flag input is unconditional branch.
PC14 pfcu (
	.flags({carry,zero,ovflo,1'b1}),	// status flags
	.paddr(paddr),							// address of next intruction
	.pdata(pdata),							// current instruction
	.rdata(a[13:0]),						// data from A register
	.ce(~inrd1),							// PC count enable (low for 1st cycle of 2-cycle instructions)
	.clk(clk),
	.rst(rst)
	);
assign pcs = ~inrd1;	// enable program RAM output
// assign fields for load and data manipulation instuctions (program control decoded elsewhere)
assign mod = pdata[10:8];					// operation modifier
assign op = pdata[13:11];					// operation code field
assign typ = pdata[15:14];					// instruction type field
assign write = (typ == 2) & (op == 6);	// memory write operation
assign out = (typ == 2) & (op == 7);	// Output operation
assign inp = (typ == 3) & (op == 0);	// Input operation
assign read = (typ == 3) & (op == 1);	// memory read operation
// decode input and read instructions cycle 1 and cycle 2
assign inrd1 = (inp|read) & ~inrd2;
always @ (posedge clk)
	if (rst) inrd2 <= 0;
	else inrd2 <= inrd1;
// ALU provides memory address on B and data for memory writes or outputs on A
ALU16 alu (
	.a(a),				// ALU register A output
	.b(b),				// ALU register B output
	.d0(din),			// data from I/O port to ALU
	.d1(min),			// data from memory to ALU
	.pdata(pdata),		// instruction input
	.zero(zero),		// zero, carry and overflow flags from ALU
	.carry(carry),
	.ovflo(ovflo),
	.clk(clk),			// for flags
	.rst(rst)
	);
// Memory Bus
assign maddr = b[13:0] + {11'b00000000000,mod};	// 14-bit memory address
assign mout = a;					// 16-bit data from register A
assign mwr = write;				// write to memory
// I/O Bus
assign ioaddr = pdata[10:4];	// 7-bit I/O address
assign dout = a;					// 16-bit data from register A
assign iord = inp & inrd1;		// read from input port (strobe on 1st cycle only)
assign iowr = out;				// write to output port
endmodule
