I'm trying to create an instruction decoder in Verilog using Xilinx. My apologies for not having the cleanest code, I'm still learning Verilog. The issue I am having is that my FS result is incorrect.
I expect to see 00010 but instead I see 01010. As I debug, I changed the FS non-blocking assignment for ADD from 00010 to 01010 just to see what the result would be and I end up with FS being 10010. This leads me to believe that the bit[3] of FS is adding an extra 1 somehow. This is my verilog code:
`timescale 1ns / 1ps
`include "OPCODES.vh"
module instructiondecoder(
input [31:0] instruction,
//Control Word Values
output reg RW,
output reg [1:0] MD,
output reg [1:0] BS,
output reg PS,
output reg MW,
output reg [4:0] FS,
output reg MB,
output reg MA,
output reg CS,
output [4:0] AA,
output [4:0] BA
);
assign AA = instruction[19:15];
assign BA = instruction[14:10];
initial begin
RW <= 0;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00000;
MB <= 0;
MA <= 0;
CS <= 0;
end
always @ (instruction)
begin
case(instruction[31:25])
`NOP:
begin
RW <= 0;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00000;
MB <= 0;
MA <= 0;
CS <= 0;
end
`ADD:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00010;
MB <= 0;
MA <= 0;
CS <= 0;
end
`SUB:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00101;
MB <= 0;
MA <= 0;
CS <= 0;
end
`SLT:
begin
RW <= 1;
MD <= 10;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00101;
MB <= 0;
MA <= 0;
CS <= 0;
end
`AND:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 01000;
MB <= 0;
MA <= 0;
CS <= 0;
end
`OR:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 01010;
MB <= 0;
MA <= 0;
CS <= 0;
end
`XOR:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 01100;
MB <= 0;
MA <= 0;
CS <= 0;
end
`ST:
begin
RW <= 0;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 1;
FS <= 00000;
MB <= 0;
MA <= 0;
CS <= 0;
end
`LD:
begin
RW <= 1;
MD <= 01;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00000;
MB <= 0;
MA <= 0;
CS <= 0;
end
`ADI:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00010;
MB <= 1;
MA <= 0;
CS <= 1;
end
`SBI:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00101;
MB <= 1;
MA <= 0;
CS <= 1;
end
`NOT:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 01110;
MB <= 0;
MA <= 0;
CS <= 0;
end
`ANI:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 01000;
MB <= 1;
MA <= 0;
CS <= 0;
end
`ORI:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 01010;
MB <= 1;
MA <= 0;
CS <= 0;
end
`XRI:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 01100;
MB <= 1;
MA <= 0;
CS <= 0;
end
`AIU:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00010;
MB <= 1;
MA <= 0;
CS <= 0;
end
`SIU:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00101;
MB <= 1;
MA <= 0;
CS <= 0;
end
`MOV:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00000;
MB <= 0;
MA <= 0;
CS <= 0;
end
`LSL:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 10100;
MB <= 0;
MA <= 0;
CS <= 0;
end
`LSR:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 11000;
MB <= 0;
MA <= 0;
CS <= 0;
end
`JMR:
begin
RW <= 1;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 11000;
MB <= 0;
MA <= 0;
CS <= 0;
end
`BZ:
begin
RW <= 0;
MD <= 00;
BS <= 01;
PS <= 0;
MW <= 0;
FS <= 00000;
MB <= 1;
MA <= 0;
CS <= 1;
end
`BNZ:
begin
RW <= 0;
MD <= 00;
BS <= 01;
PS <= 1;
MW <= 0;
FS <= 00000;
MB <= 1;
MA <= 0;
CS <= 1;
end
`JMP:
begin
RW <= 0;
MD <= 00;
BS <= 11;
PS <= 0;
MW <= 0;
FS <= 00000;
MB <= 1;
MA <= 0;
CS <= 1;
end
`JML:
begin
RW <= 1;
MD <= 00;
BS <= 11;
PS <= 0;
MW <= 0;
FS <= 00111;
MB <= 1;
MA <= 1;
CS <= 1;
end
default :
begin
RW <= 1'bx;
MD <= 2'bxx;
BS <= 2'bxx;
PS <= 1'bx;
MW <= 1'bx;
FS <= 5'bxxxxx;
MB <= 1'bx;
MA <= 1'bx;
CS <= 1'bx;
end
endcase
end
endmodule
The following is my OPCODES include:
`ifndef OP_CODES
`define OP_CODES
`define NOP 7'b0000000
`define ADD 7'b0000010
`define SUB 7'b0000101
`define SLT 7'b1100010
`define AND 7'b0001000
`define OR 7'b0001010
`define XOR 7'b0001100
`define ST 7'b0000001
`define LD 7'b0100001
`define ADI 7'b0100010
`define SBI 7'b0100101
`define NOT 7'b0101110
`define ANI 7'b0101000
`define ORI 7'b0101010
`define XRI 7'b0101100
`define AIU 7'b1100010
`define SIU 7'b1000101
`define MOV 7'b1000000
`define LSL 7'b0110000
`define LSR 7'b0110001
`define JMR 7'b1100001
`define BZ 7'b0100000
`define BNZ 7'b1100000
`define JMP 7'b1000100
`define JML 7'b0000111
`endif
And in this is my test:
`timescale 1ns / 1ps
`include "OPCODES.vh"
module instructionDecoder_test;
// Inputs
reg [31:0] instruction;
// Outputs
wire RW;
wire [1:0] MD;
wire [1:0] BS;
wire PS;
wire MW;
wire [4:0] FS;
wire MA;
wire MB;
wire CS;
wire [4:0] AA;
wire [4:0] BA;
// Instantiate the Unit Under Test (UUT)
instructiondecoder uut (
.instruction(instruction),
.RW(RW),
.MD(MD),
.BS(BS),
.PS(PS),
.MW(MW),
.FS(FS),
.MA(MA),
.MB(MB),
.CS(CS),
.AA(AA),
.BA(BA)
);
initial begin
// Initialize Inputs
// Wait 100 ns for global reset to finish
#100;
instruction = {`ADD, 5'd8, 5'd3, 5'd5, 10'b0}; //ADD
end
endmodule
When you write (below) the Right hand side is an Integer (Decimal, base10), not binary (base2). Only use non-blocking when implying flip-flops.
initial begin
RW <= 0;
MD <= 00;
BS <= 00;
PS <= 0;
MW <= 0;
FS <= 00000;
MB <= 0;
MA <= 0;
CS <= 0;
end
What you want is:
initial begin
RW = 'b0 ;
MD = 'b00 ;
BS = 'b00 ;
PS = 'b0 ;
MW = 'b0 ;
FS = 'b00000;
MB = 'b0 ;
MA = 'b0 ;
CS = 'b0 ;
end
NB: You do not need to to include leading 0's although it can help readability.
To add to Will's comment, It is recommended to size your numbers (5'b10110
instead of 'b10110
), I do however tend to leave reset or initial conditions un-sized to minimise the refactoring required for code changes.
Other available options for number bases in verilog are:
'b0 // Binary (base2)
'o0 // Octal (base8)
'd0 // Decimal (base10)
'h0 // Hexadecimal (base16)