Hi, All.
In case anyone would like to offer opinions on it, I'm designing a
super-simple CPU for educational purposes. I'm going to use it in my
graduate computer architecture course this Autumn, and I'll be posting code
as I go along. Here are some of my motivations:
1. It needs to be readable and easy to follow.
2. It needs to be easy to modify.
3. No fancy instructions. Just the minimal basics.
4. It should be small.
5. We should make elements of it synthesizable only if it can be justified
in terms of having educational value and not hurting readability too much.
6. It needs to be modular to help compartmentalize concepts.
7 It needs to simulate, of course.
8. Above all, the objective is to teach ARCHITECTURE. ISA design, for
instance, while important, can be decoupled from architecture.
I'm sure I can think of others, but you get the general idea. I thought
about using the OGA2 ISA (stripped down), but that's too complicated. I
like predication and being able to choose per-instruction whether or not
the PSW/CC is set, but those add complexity that may distract from teaching
architecture. I think I will still make R0 a bit bucket, but only because
it reduces the number of opcodes I have to deal with. It will be a
challenge for me to resist making synthesizable code in places where doing
that will obscure the idea being represented.
Below is an early draft of the ALU. It needs some cleanup and more
comments.
module simple_alu(
input clock,
input _reset,
input [31:0] operandA,
input [31:0] operandB,
input [`NUM_OP_BITS-1:0] operation_in,
output reg [31:0] result,
output reg [`NUM_FLAG_BITS-1:0] flags,
output reg [`NUM_OP_BITS-1:0] operation_out);
// Add and subtract
wire [31:0] invB = {32{operation_in[0]}} ^ operandB; // 1's complement of
B
wire [33:0] sum = {operandA, 1b'1} + {operandB,
operation_in[`INT_CARRY_IN]};
// Notes:
// To add without carry, carry-in must be clear
// To substract without borrow, carry-in must be set
// Shifts
wire in_from_left = operation_in[0] ? operandA[31] :
operation_in[`INT_CARRY_IN];
wire [31:0] rshift_ext = {32{in_from_left}};
wire [31:0] rshift = {rshift_ext, operandA} >> operandB[4:0];
wire [31:0] lshift_ext = {32{operation_in[`INT_CARRY_IN]}};
wire [63:0] lshift = {operandA, lshift_ext} << operandB[4:0];
// Bus to hold result of computation
reg [32:0] value;
// Compute result
always @(*) begin
case (operation_in)
INT_ADD,
INT_SUB: value = sum[33:1];
INT_LSR,
INT_ASR: value = rshift;
INT_LSL: value = lshift[63:32];
INT_AND: value = operandA & operandB;
INT_OR: value = operandA | operandB;
INT_XOR: value = operandA ^ operandB;
endcase
end
// Compute condition code flags
wire ovl = (operandA[31] == operandB[31]) && (operandA[31] != value[31]);
wire zero = (value == 0);
wire neg = value[31];
wire carry = value[32];
// Register result
always @(posedge clock, negedge _reset) begin
if (_reset == 0) begin
result <= 0;
flags <= 0;
operation_out <= 0;
end else begin
operation_out <= operation_in;
flags <= {ovl, zero, neg, carry};
result <= value[31:0];
end
end
endmodule
--
Timothy Normand Miller, PhD
Assistant Professor of Computer Science, Binghamton University
http://www.cs.binghamton.edu/~millerti/
Open Graphics Project
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)