RAM Test

Download: ramtest.zip

This project tests the memory access actions of a simple computer. The load instruction (Opcode 0x01) reads data from a specified memory address into the accumulator. The store instruction (Opcode 0x04) writes data from the accumulator into a specified memory address.

Memory can be examined in the simulator after running the program by clicking on the Logical Memories section in the left column of the simulation report tree list.

Instruction MnemonicOperation PerformedOpcode
LOAD addressAC ← contents of memory address01
ADD addressAC ← AC + contents of memory address02
SUB addressAC ← AC − contents of memory address 03
STORE addresscontents of memory address ← AC04
JUMP addressPC ← address05
JNEG addressIf AC < 0 then PC ← address06

Example

  C = A + B

If we assume that A is stored in address 0x10, B is in address 0x11, and the result C should be stored in 0x12, then we have the following program:

Assembly LanguageMachine Language
LOAD B0111
ADD A 0210
STORE C0412

Architecture

PCProgram counter
IRInstruction register
ACAccumulator
MARMemory address register
MDRMemory data register

Parametric Modules

Memory Initialization File (.MIF)

DEPTH = 256;	% Memory depth and width are required	%
WIDTH = 16;	% Enter a decimal number	%

ADDRESS_RADIX = HEX;	% Address and value radixes are optional %
DATA_RADIX = HEX;	% Enter BIN, DEC, HEX, or OCT; unless %
			% otherwise specified, radixes = HEX	%
-- Specify values for addresses, single address or range
CONTENT
	BEGIN
[00..FF]	:      0000;  % Range--00 to FF = 0000 %
   00		:      0112;  % Load MEM[12] %
   01		:      0110;  % Load MEM[10] %
   02		:      0412;  % Store MEM[12]%
   03           :      0111;  % Load MEM[11] %
   04		:      0112;  % Load MEM[12] %
   05		:      0113;  % Load MEM[13] %
   10		:      0AAA;
   11		:      0BBB;
   12		:      0123;
   13          :      0DDD;
END ;	

Simulation

Setting mem_address

always
case (state)
reset_pc: mem_address <= 8'h00;
decode:  mem_address <= mem_data_out[7:0];
execute: mem_address <= pc;
store1:  mem_address <= data_address;
store2:  mem_address <= pc;
default: mem_address <= 8'hff;
endcase

Simulation: Load Values

mem_address changes when state changes (combinational process)

State Machine: reset_pc

always @(posedge clock, negedge reset)
	begin
	if (~reset) state<=reset_pc;
	else
	case (state)
	reset_pc :
		begin
		pc <= 8'h00;
		data_register <= 16'h0000;
		state <= decode;
		end

State Machine: decode

// decode opcode, increment program counter
	decode :
		begin
		pc <= pc + 8'h01;
		data_address <= mem_data_out[7:0];
		// decode opcode
		case (opcode)
		8'h01 : // load
			state <= execute;
		8'h04 : // store
			state <= store1;
		default:
			state <= decode;
		endcase
		end

State Machine: execute, store

// execute instruction, save data
	execute :
		begin
		data_register <= mem_data_out;
		state <= decode;
		end
	store1 : state <= store2;
	store2 : state <= decode;
	// default state transition
	default : state <= decode;
	endcase
	end

Simulation: Store Values

assign write_enable = (state==store1);

Verilog Code

ramtest.v

module ramtest(clock, reset, mem_address, mem_data_out, 
    data_register, pc, write_enable);
input clock, reset;
output [15:0] mem_data_out;
output [15:0] data_register;
output [7:0] pc;
output [7:0] mem_address;
//output [2:0] state;
reg [2:0] state;
reg [15:0] data_register;
reg [7:0] pc;

reg [7:0] mem_address;
reg [7:0] data_address;
output write_enable;

wire [7:0] opcode;
assign opcode = mem_data_out[15:8];

parameter
    reset_pc = 3'd0,
    decode   = 3'd1,
    execute = 3'd2,
    store1 = 3'd3,
    store2 = 3'd4;

// instantiate memory (256 16-bit words)
mem mem_component(
    .address (mem_address),
    .data (data_register),
    .inclock (clock),
    .wren (write_enable),
    .q (mem_data_out)
    );
    
//assign write_enable = (state==store1?clock:1'b0); // this fails
assign write_enable = (state==store1); // this works
    
always
case (state)
reset_pc: mem_address <= 8'h00;
decode:  mem_address <= mem_data_out[7:0];
execute: mem_address <= pc;
store1:  mem_address <= data_address;
store2:  mem_address <= pc;
default: mem_address <= 8'hff;
endcase

// finite state machine
always @(posedge clock, negedge reset)
    begin
    if (~reset) state<=reset_pc;
    else
    case (state)
    reset_pc :
        begin
        pc <= 8'h00;
        data_register <= 16'h0000;
        state <= decode;
        end
    // decode opcode, increment program counter
    decode :
        begin
        pc <= pc + 8'h01;
        data_address <= mem_data_out[7:0];
        // decode opcode
        case (opcode)
        8'h01 : // load
            state <= execute;
        8'h04 : // store
            state <= store1;
        default:
            state <= decode;
        endcase
        end
    // execute instruction, setup instruction address
    execute :
        begin
        data_register <= mem_data_out;
        state <= decode;
        end
    store1 : state <= store2;
    store2 : state <= decode;
    // default state transition
    default : state <= decode;
    endcase
    end
endmodule


Maintained by John Loomis, last updated 7 October 2008