Line 43... |
Line 43... |
//// ////
|
//// ////
|
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
|
|
`include "timescale.v"
|
`include "timescale.v"
|
|
|
module t6507lp_fsm(clk, reset_n, alu_result, alu_status, data_in, address, control, data_out, alu_opcode, alu_a, alu_enable, alu_x, alu_y);
|
module t6507lp_fsm(clk, reset_n, alu_result, alu_status, data_in, address, mem_rw, data_out, alu_opcode, alu_a, alu_enable, alu_x, alu_y);
|
parameter [3:0] DATA_SIZE = 4'd8;
|
parameter [3:0] DATA_SIZE = 4'd8;
|
parameter [3:0] ADDR_SIZE = 4'd13;
|
parameter [3:0] ADDR_SIZE = 4'd13;
|
|
|
localparam [3:0] DATA_SIZE_ = DATA_SIZE - 4'b0001;
|
localparam [3:0] DATA_SIZE_ = DATA_SIZE - 4'b0001;
|
localparam [3:0] ADDR_SIZE_ = ADDR_SIZE - 4'b0001;
|
localparam [3:0] ADDR_SIZE_ = ADDR_SIZE - 4'b0001;
|
|
|
input clk;
|
input clk; // master clock
|
input reset_n;
|
input reset_n; // active low reset
|
input [DATA_SIZE_:0] alu_result;
|
input [DATA_SIZE_:0] alu_result; // result from alu operation
|
input [DATA_SIZE_:0] alu_status;
|
input [DATA_SIZE_:0] alu_status; // alu status register
|
input [DATA_SIZE_:0] data_in;
|
input [DATA_SIZE_:0] data_in; // data that comes from the bus controller
|
output reg [ADDR_SIZE_:0] address;
|
output reg [ADDR_SIZE_:0] address; // system bus address
|
output reg control; // read = 0, write = 1
|
output reg mem_rw; // read = 0, write = 1
|
output reg [DATA_SIZE_:0] data_out;
|
output reg [DATA_SIZE_:0] data_out; // data that will be written somewhere else
|
output reg [DATA_SIZE_:0] alu_opcode;
|
output reg [DATA_SIZE_:0] alu_opcode; // current opcode
|
output reg [DATA_SIZE_:0] alu_a;
|
output reg [DATA_SIZE_:0] alu_a; // extra operand sent to the alu
|
output reg alu_enable;
|
output reg alu_enable; // a flag that when high tells the alu when to perform the operations
|
|
|
input [DATA_SIZE_:0] alu_x;
|
input [DATA_SIZE_:0] alu_x;
|
input [DATA_SIZE_:0] alu_y;
|
input [DATA_SIZE_:0] alu_y;
|
|
|
// FSM states. If aiming for less power consumption try gray coding.
|
// FSM states. If aiming for less power consumption try gray coding.
|
localparam FETCH_OP = 5'b00000;
|
|
//localparam FETCH_OP_CALC = 5'b00001; this was never used
|
//localparam FETCH_OP_CALC = 5'b00001; this was never used
|
|
localparam FETCH_OP = 5'b00000;
|
localparam FETCH_LOW = 5'b00010;
|
localparam FETCH_LOW = 5'b00010;
|
localparam FETCH_HIGH = 5'b00011;
|
localparam FETCH_HIGH = 5'b00011;
|
localparam READ_MEM = 5'b00100;
|
localparam READ_MEM = 5'b00100;
|
localparam DUMMY_WRT_CALC = 5'b00101;
|
localparam DUMMY_WRT_CALC = 5'b00101;
|
localparam WRITE_MEM = 5'b00110;
|
localparam WRITE_MEM = 5'b00110;
|
Line 100... |
Line 100... |
localparam RESET = 5'b11111;
|
localparam RESET = 5'b11111;
|
|
|
// OPCODES TODO: verify how this get synthesised
|
// OPCODES TODO: verify how this get synthesised
|
`include "T6507LP_Package.v"
|
`include "T6507LP_Package.v"
|
|
|
// control signals
|
// mem_rw signals
|
localparam MEM_READ = 1'b0;
|
localparam MEM_READ = 1'b0;
|
localparam MEM_WRITE = 1'b1;
|
localparam MEM_WRITE = 1'b1;
|
|
|
reg [ADDR_SIZE_:0] pc; // program counter
|
reg [ADDR_SIZE_:0] pc; // program counter
|
reg [DATA_SIZE:0] sp; // stack pointer. 9 bits wide.
|
reg [DATA_SIZE:0] sp; // stack pointer. 9 bits wide.
|
Line 205... |
Line 205... |
temp_addr <= 13'h0000;
|
temp_addr <= 13'h0000;
|
temp_data <= 8'h00;
|
temp_data <= 8'h00;
|
state <= RESET;
|
state <= RESET;
|
// registered outputs also receive default values
|
// registered outputs also receive default values
|
address <= 0;
|
address <= 0;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
else begin
|
else begin
|
state <= next_state;
|
state <= next_state;
|
|
|
Line 223... |
Line 223... |
FETCH_OP_CALC_PARAM: enables the alu with an argument (alu_a) and fetchs the next instruction opcode. (pipelining)
|
FETCH_OP_CALC_PARAM: enables the alu with an argument (alu_a) and fetchs the next instruction opcode. (pipelining)
|
*/
|
*/
|
FETCH_OP, FETCH_OP_CALC_PARAM: begin // this is the pipeline happening!
|
FETCH_OP, FETCH_OP_CALC_PARAM: begin // this is the pipeline happening!
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= next_pc;
|
address <= next_pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
ir <= data_in;
|
ir <= data_in;
|
end
|
end
|
/*
|
/*
|
in this state the opcode is already known so truly execution begins.
|
in this state the opcode is already known so truly execution begins.
|
all instruction execute this cycle.
|
all instruction execute this cycle.
|
*/
|
*/
|
FETCH_LOW: begin
|
FETCH_LOW: begin
|
if (accumulator || implied) begin
|
if (accumulator || implied) begin
|
pc <= pc; // is this better?
|
pc <= pc; // is this better?
|
address <= pc;
|
address <= pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
else if (immediate || relative) begin
|
else if (immediate || relative) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= next_pc;
|
address <= next_pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
temp_data <= data_in; // the follow-up byte is saved in temp_data
|
temp_data <= data_in; // the follow-up byte is saved in temp_data
|
end
|
end
|
else if (absolute || absolute_indexed || jump_indirect) begin
|
else if (absolute || absolute_indexed || jump_indirect) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= next_pc;
|
address <= next_pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
temp_addr <= {{5{1'b0}},data_in};
|
temp_addr <= {{5{1'b0}},data_in};
|
temp_data <= 8'h00;
|
temp_data <= 8'h00;
|
end
|
end
|
else if (zero_page) begin
|
else if (zero_page) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= {{5{1'b0}},data_in};
|
address <= {{5{1'b0}},data_in};
|
temp_addr <= {{5{1'b0}},data_in};
|
temp_addr <= {{5{1'b0}},data_in};
|
|
|
if (write) begin
|
if (write) begin
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
data_out <= alu_result;
|
data_out <= alu_result;
|
end
|
end
|
else begin
|
else begin
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
end
|
end
|
else if (zero_page_indexed) begin
|
else if (zero_page_indexed) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= {{5{1'b0}}, data_in};
|
address <= {{5{1'b0}}, data_in};
|
temp_addr <= {{5{1'b0}}, data_in};
|
temp_addr <= {{5{1'b0}}, data_in};
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
else if (indirectx || indirecty) begin
|
else if (indirectx || indirecty) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= data_in;
|
address <= data_in;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
else begin // the special instructions will fall here: BRK, RTI, RTS...
|
else begin // the special instructions will fall here: BRK, RTI, RTS...
|
if (brk) begin
|
if (brk) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= sp;
|
address <= sp;
|
data_out <= {{3{1'b0}}, pc[12:8]};
|
data_out <= {{3{1'b0}}, pc[12:8]};
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
end
|
end
|
else if (rti || rts) begin
|
else if (rti || rts) begin
|
address <= sp;
|
address <= sp;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
else if (pha || php) begin
|
else if (pha || php) begin
|
pc <= pc;
|
pc <= pc;
|
address <= sp;
|
address <= sp;
|
data_out <= (pha) ? alu_result : alu_status;
|
data_out <= (pha) ? alu_result : alu_status;
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
end
|
end
|
else if (pla || plp) begin
|
else if (pla || plp) begin
|
pc <= pc;
|
pc <= pc;
|
address <= sp;
|
address <= sp;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
else begin // jsr
|
else begin // jsr
|
address <= sp;
|
address <= sp;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
temp_addr <= {{5{1'b0}}, data_in};
|
temp_addr <= {{5{1'b0}}, data_in};
|
pc <= next_pc;
|
pc <= next_pc;
|
end
|
end
|
end
|
end
|
end
|
end
|
FETCH_HIGH_CALC_INDEX: begin
|
FETCH_HIGH_CALC_INDEX: begin
|
pc <= next_pc;
|
pc <= next_pc;
|
temp_addr[12:8] <= data_in[4:0];
|
temp_addr[12:8] <= data_in[4:0];
|
address <= {data_in[4:0], address_plus_index[7:0]};
|
address <= {data_in[4:0], address_plus_index[7:0]};
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
// this cycle fetchs the next operand while still evaluating if a branch occurred.
|
// this cycle fetchs the next operand while still evaluating if a branch occurred.
|
FETCH_OP_EVAL_BRANCH: begin
|
FETCH_OP_EVAL_BRANCH: begin
|
if (branch) begin
|
if (branch) begin
|
pc <= {{5{1'b0}}, address_plus_index[7:0]};
|
pc <= {{5{1'b0}}, address_plus_index[7:0]};
|
address <= {{5{1'b0}}, address_plus_index[7:0]};
|
address <= {{5{1'b0}}, address_plus_index[7:0]};
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
else begin
|
else begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= next_pc;
|
address <= next_pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
ir <= data_in;
|
ir <= data_in;
|
end
|
end
|
end
|
end
|
// sometimes when reading memory page crosses may occur. the pc register must be fixed, i.e., add 16'h0100
|
// sometimes when reading memory page crosses may occur. the pc register must be fixed, i.e., add 16'h0100
|
Line 337... |
Line 337... |
address[12:8] <= address_plus_index[12:8];
|
address[12:8] <= address_plus_index[12:8];
|
end
|
end
|
else begin
|
else begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= next_pc;
|
address <= next_pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
ir <= data_in;
|
ir <= data_in;
|
end
|
end
|
end
|
end
|
// several instructions ocupy 3 bytes in memory. this cycle reads the third byte.
|
// several instructions ocupy 3 bytes in memory. this cycle reads the third byte.
|
FETCH_HIGH: begin
|
FETCH_HIGH: begin
|
if (jump) begin
|
if (jump) begin
|
pc <= {data_in[4:0], temp_addr[7:0]}; // PCL <= first byte, PCH <= second byte
|
pc <= {data_in[4:0], temp_addr[7:0]}; // PCL <= first byte, PCH <= second byte
|
address <= {data_in[4:0], temp_addr[7:0]};
|
address <= {data_in[4:0], temp_addr[7:0]};
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
else begin
|
else begin
|
if (write) begin
|
if (write) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
temp_addr[12:8] <= data_in[4:0];
|
temp_addr[12:8] <= data_in[4:0];
|
address <= {data_in[4:0],temp_addr[7:0]};
|
address <= {data_in[4:0],temp_addr[7:0]};
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
data_out <= alu_result;
|
data_out <= alu_result;
|
end
|
end
|
else begin // read_modify_write or just read
|
else begin // read_modify_write or just read
|
pc <= next_pc;
|
pc <= next_pc;
|
temp_addr[12:8] <= data_in[4:0];
|
temp_addr[12:8] <= data_in[4:0];
|
address <= {data_in[4:0],temp_addr[7:0]};
|
address <= {data_in[4:0],temp_addr[7:0]};
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
end
|
end
|
end
|
end
|
READ_MEM: begin
|
READ_MEM: begin
|
if (read_modify_write) begin
|
if (read_modify_write) begin
|
pc <= pc;
|
pc <= pc;
|
address <= temp_addr;
|
address <= temp_addr;
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
data_out <= data_in; // writeback the same value
|
data_out <= data_in; // writeback the same value
|
end
|
end
|
else begin
|
else begin
|
pc <= pc;
|
pc <= pc;
|
address <= pc;
|
address <= pc;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
end
|
end
|
READ_MEM_CALC_INDEX: begin
|
READ_MEM_CALC_INDEX: begin
|
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr <= address_plus_index;
|
temp_addr <= address_plus_index;
|
|
|
if (write) begin
|
if (write) begin
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
data_out <= alu_result;
|
data_out <= alu_result;
|
end
|
end
|
else begin
|
else begin
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
|
|
end
|
end
|
READ_MEM_FIX_ADDR: begin
|
READ_MEM_FIX_ADDR: begin
|
if (read) begin
|
if (read) begin
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
|
|
if (page_crossed) begin
|
if (page_crossed) begin
|
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr <= address_plus_index;
|
temp_addr <= address_plus_index;
|
Line 411... |
Line 411... |
address <= pc;
|
address <= pc;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
end
|
end
|
end
|
end
|
else if (write) begin
|
else if (write) begin
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
data_out <= alu_result;
|
data_out <= alu_result;
|
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr <= address_plus_index;
|
temp_addr <= address_plus_index;
|
|
|
end
|
end
|
else begin // read modify write
|
else begin // read modify write
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr <= address_plus_index;
|
temp_addr <= address_plus_index;
|
end
|
end
|
end
|
end
|
DUMMY_WRT_CALC: begin
|
DUMMY_WRT_CALC: begin
|
pc <= pc;
|
pc <= pc;
|
address <= temp_addr;
|
address <= temp_addr;
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
data_out <= alu_result;
|
data_out <= alu_result;
|
end
|
end
|
WRITE_MEM: begin
|
WRITE_MEM: begin
|
pc <= pc;
|
pc <= pc;
|
address <= pc;
|
address <= pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
READ_FROM_POINTER: begin
|
READ_FROM_POINTER: begin
|
if (jump_indirect) begin
|
if (jump_indirect) begin
|
pc[7:0] <= data_in;
|
pc[7:0] <= data_in;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
address <= address_plus_index;
|
address <= address_plus_index;
|
end
|
end
|
else begin
|
else begin
|
pc <= pc;
|
pc <= pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
|
|
if (indirectx) begin
|
if (indirectx) begin
|
address <= address_plus_index;
|
address <= address_plus_index;
|
end
|
end
|
else begin // indirecty falls here
|
else begin // indirecty falls here
|
Line 459... |
Line 459... |
end
|
end
|
READ_FROM_POINTER_X: begin
|
READ_FROM_POINTER_X: begin
|
pc <= pc;
|
pc <= pc;
|
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr[7:0] <= data_in;
|
temp_addr[7:0] <= data_in;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
READ_FROM_POINTER_X1: begin
|
READ_FROM_POINTER_X1: begin
|
if (jump_indirect) begin
|
if (jump_indirect) begin
|
pc[12:8] <= data_in[4:0];
|
pc[12:8] <= data_in[4:0];
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
address <= {data_in[4:0], pc[7:0]};
|
address <= {data_in[4:0], pc[7:0]};
|
end
|
end
|
else if (indirectx) begin
|
else if (indirectx) begin
|
address <= {data_in[4:0], temp_addr[7:0]};
|
address <= {data_in[4:0], temp_addr[7:0]};
|
if (write) begin
|
if (write) begin
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
data_out <= alu_result;
|
data_out <= alu_result;
|
end
|
end
|
else begin
|
else begin
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
end
|
end
|
else begin // indirecty falls here
|
else begin // indirecty falls here
|
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr[12:8] <= data_in;
|
temp_addr[12:8] <= data_in;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
end
|
end
|
PUSH_PCH: begin
|
PUSH_PCH: begin
|
pc <= pc;
|
pc <= pc;
|
address <= sp_minus_one;
|
address <= sp_minus_one;
|
data_out <= pc[7:0];
|
data_out <= pc[7:0];
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
sp <= sp_minus_one;
|
sp <= sp_minus_one;
|
end
|
end
|
PUSH_PCL: begin
|
PUSH_PCL: begin
|
if (jsr) begin
|
if (jsr) begin
|
pc <= pc;
|
pc <= pc;
|
address <= pc;
|
address <= pc;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
sp <= sp_minus_one;
|
sp <= sp_minus_one;
|
end
|
end
|
else begin
|
else begin
|
pc <= pc;
|
pc <= pc;
|
address <= sp_minus_one;
|
address <= sp_minus_one;
|
data_out <= alu_status;
|
data_out <= alu_status;
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
sp <= sp_minus_one;
|
sp <= sp_minus_one;
|
end
|
end
|
end
|
end
|
PUSH_STATUS: begin
|
PUSH_STATUS: begin
|
address <= 13'hFFFE;
|
address <= 13'hFFFE;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
FETCH_PCL: begin
|
FETCH_PCL: begin
|
pc[7:0] <= data_in;
|
pc[7:0] <= data_in;
|
address <= 13'hFFFF;
|
address <= 13'hFFFF;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
FETCH_PCH: begin
|
FETCH_PCH: begin
|
pc[12:8] <= data_in[4:0];
|
pc[12:8] <= data_in[4:0];
|
address <= {data_in[4:0], pc[7:0]};
|
address <= {data_in[4:0], pc[7:0]};
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
end
|
end
|
INCREMENT_SP: begin
|
INCREMENT_SP: begin
|
sp <= sp_plus_one;
|
sp <= sp_plus_one;
|
address <= sp_plus_one;
|
address <= sp_plus_one;
|
end
|
end
|
Line 545... |
Line 545... |
end
|
end
|
PUSH_REGISTER: begin
|
PUSH_REGISTER: begin
|
pc <= pc;
|
pc <= pc;
|
address <= pc;
|
address <= pc;
|
sp <= sp_minus_one;
|
sp <= sp_minus_one;
|
control <= MEM_READ;
|
mem_rw <= MEM_READ;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
end
|
end
|
PULL_REGISTER: begin
|
PULL_REGISTER: begin
|
pc <= pc;
|
pc <= pc;
|
address <= pc;
|
address <= pc;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
end
|
end
|
DUMMY: begin
|
DUMMY: begin
|
address <= sp;
|
address <= sp;
|
control <= MEM_WRITE;
|
mem_rw <= MEM_WRITE;
|
end
|
end
|
default: begin
|
default: begin
|
$write("unknown state"); // TODO: check if synth really ignores this 2 lines. Otherwise wrap it with a `ifdef
|
$write("unknown state"); // TODO: check if synth really ignores this 2 lines. Otherwise wrap it with a `ifdef
|
$finish(0);
|
$finish(0);
|
end
|
end
|