Line 83... |
Line 83... |
localparam FETCH_OP_EVAL_BRANCH = 5'b01011;
|
localparam FETCH_OP_EVAL_BRANCH = 5'b01011;
|
localparam FETCH_OP_FIX_PC = 5'b01100;
|
localparam FETCH_OP_FIX_PC = 5'b01100;
|
localparam READ_FROM_POINTER = 5'b01101;
|
localparam READ_FROM_POINTER = 5'b01101;
|
localparam READ_FROM_POINTER_X = 5'b01110;
|
localparam READ_FROM_POINTER_X = 5'b01110;
|
localparam READ_FROM_POINTER_X1 = 5'b01111;
|
localparam READ_FROM_POINTER_X1 = 5'b01111;
|
|
localparam PUSH_PCH = 5'b10000;
|
|
localparam PUSH_PCL = 5'b10001;
|
|
localparam PUSH_STATUS = 5'b10010;
|
|
localparam FETCH_PCL = 5'b10011;
|
|
localparam FETCH_PCH = 5'b10100;
|
|
|
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"
|
Line 94... |
Line 99... |
// control signals
|
// control 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 [ADDR_SIZE_:0] sp; // stack pointer
|
reg [DATA_SIZE:0] sp; // stack pointer. 9 bits wide.
|
reg [DATA_SIZE_:0] ir; // instruction register
|
reg [DATA_SIZE_:0] ir; // instruction register
|
reg [ADDR_SIZE_:0] temp_addr; // temporary address
|
reg [ADDR_SIZE_:0] temp_addr; // temporary address
|
reg [DATA_SIZE_:0] temp_data; // temporary data
|
reg [DATA_SIZE_:0] temp_data; // temporary data
|
|
|
reg [4:0] state, next_state; // current and next state registers
|
reg [4:0] state, next_state; // current and next state registers
|
// TODO: not sure if this will be 4 bits wide. as of march 9th this was 4bit wide.
|
// TODO: not sure if this will be 5 bits wide. as of march 24th this was 5bit wide.
|
|
|
// wiring that simplifies the FSM logic
|
// wiring that simplifies the FSM logic by simplifying the addressing modes
|
reg absolute;
|
reg absolute;
|
reg absolute_indexed;
|
reg absolute_indexed;
|
reg accumulator;
|
reg accumulator;
|
reg immediate;
|
reg immediate;
|
reg implied;
|
reg implied;
|
Line 122... |
Line 127... |
reg read_modify_write;
|
reg read_modify_write;
|
reg write;
|
reg write;
|
reg jump;
|
reg jump;
|
reg jump_indirect;
|
reg jump_indirect;
|
|
|
|
// regs for the special instructions
|
|
reg break;
|
|
|
wire [ADDR_SIZE_:0] next_pc;
|
wire [ADDR_SIZE_:0] next_pc;
|
assign next_pc = pc + 13'b0000000000001;
|
assign next_pc = pc + 13'b0000000000001;
|
|
|
reg [ADDR_SIZE_:0] address_plus_index; // this would update more times than actually needed, consuming power.
|
reg [ADDR_SIZE_:0] address_plus_index; // this would update more times than actually needed, consuming power.
|
reg page_crossed; // so the simple assign was changed into a combinational always block
|
reg page_crossed; // so the simple assign was changed into a combinational always block
|
Line 192... |
Line 200... |
end
|
end
|
else begin
|
else begin
|
state <= next_state;
|
state <= next_state;
|
|
|
case (state)
|
case (state)
|
RESET: begin
|
RESET: begin // The processor was reset
|
// The processor was reset
|
|
$write("under reset");
|
$write("under reset");
|
end
|
end
|
FETCH_OP: begin // this state is the simplest one. it is a simple fetch that must be done when the cpu was reset or
|
/*
|
// the last cycle was a memory write.
|
FETCH_OP: executed when the processor was reset or the last instruction could not fetch.
|
|
FETCH_OP_CALC: enables the alu 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, 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;
|
control <= MEM_READ;
|
ir <= data_in;
|
ir <= data_in;
|
end
|
end
|
FETCH_OP_CALC, FETCH_OP_CALC_PARAM: begin // this is the pipeline happening!
|
/*
|
pc <= next_pc;
|
in this state the opcode is already known so truly execution begins.
|
address <= next_pc;
|
all instruction execute this cycle.
|
control <= MEM_READ;
|
*/
|
ir <= data_in;
|
FETCH_LOW: begin
|
end
|
|
FETCH_LOW: begin // in this state the opcode is already known so truly execution begins
|
|
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;
|
control <= MEM_READ;
|
end
|
end
|
Line 255... |
Line 264... |
address <= data_in;
|
address <= data_in;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
control <= MEM_READ;
|
control <= 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 (break) begin
|
|
pc <= next_pc;
|
|
address <= sp;
|
|
data_out <= {{3{1'b0}}, pc[12:8]};
|
|
control <= MEM_WRITE;
|
|
sp <= sp_minus_one;
|
|
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;
|
control <= 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.
|
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;
|
control <= MEM_READ;
|
Line 280... |
Line 296... |
control <= MEM_READ;
|
control <= 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
|
FETCH_OP_FIX_PC: begin
|
FETCH_OP_FIX_PC: begin
|
if (page_crossed) begin
|
if (page_crossed) begin
|
pc[12:8] <= address_plus_index[12:8];
|
pc[12:8] <= address_plus_index[12:8];
|
address[12:8] <= address_plus_index[12:8];
|
address[12:8] <= address_plus_index[12:8];
|
end
|
end
|
Line 292... |
Line 309... |
address <= next_pc;
|
address <= next_pc;
|
control <= MEM_READ;
|
control <= 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.
|
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;
|
control <= MEM_READ;
|
Line 438... |
Line 456... |
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr[12:8] <= data_in;
|
temp_addr[12:8] <= data_in;
|
control <= MEM_READ;
|
control <= MEM_READ;
|
end
|
end
|
end
|
end
|
|
PUSH_PCH: begin
|
|
pc <= pc;
|
|
address <= sp;
|
|
data_out <= pc[7:0];
|
|
control <= MEM_WRITE;
|
|
sp <= sp_minus_one;
|
|
end
|
|
PUSH_PCL: begin
|
|
pc <= pc;
|
|
address <= sp;
|
|
data_out <= alu_status;
|
|
control <= MEM_WRITE;
|
|
sp <= sp_minus_one;
|
|
end
|
|
PUSH_STATUS: begin
|
|
address <= 13'hFFFE;
|
|
control <= MEM_READ;
|
|
end
|
|
FETCH_PCL: begin
|
|
pc[7:0] <= data_in;
|
|
address <= 13'hFFFF;
|
|
control <= MEM_READ;
|
|
end
|
|
FETCH_PCH: begin
|
|
pc[12:8] <= data_in[4:0];
|
|
address <= {data_in[4:0], pc[7:0]};
|
|
control <= MEM_READ;
|
|
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
|
|
|
Line 517... |
Line 563... |
end
|
end
|
else if (indirectx || indirecty) begin
|
else if (indirectx || indirecty) begin
|
next_state = READ_FROM_POINTER;
|
next_state = READ_FROM_POINTER;
|
end
|
end
|
else begin // all the special instructions will fall here
|
else begin // all the special instructions will fall here
|
next_state = RESET;
|
if (break) begin
|
|
next_state = PUSH_PCH;
|
|
end
|
end
|
end
|
end
|
end
|
READ_FROM_POINTER: begin
|
READ_FROM_POINTER: begin
|
if (indirectx) begin
|
if (indirectx) begin
|
next_state = READ_FROM_POINTER_X;
|
next_state = READ_FROM_POINTER_X;
|
Line 639... |
Line 687... |
next_state = WRITE_MEM;
|
next_state = WRITE_MEM;
|
end
|
end
|
WRITE_MEM: begin
|
WRITE_MEM: begin
|
next_state = FETCH_OP;
|
next_state = FETCH_OP;
|
end
|
end
|
|
PUSH_PCH: begin
|
|
next_state = PUSH_PCL;
|
|
end
|
|
PUSH_PCL: begin
|
|
next_state = PUSH_STATUS;
|
|
end
|
|
PUSH_STATUS: begin
|
|
next_state = FETCH_PCL;
|
|
end
|
|
FETCH_PCL: begin
|
|
next_state = FETCH_PCH;
|
|
end
|
|
FETCH_PCH: begin
|
|
next_state = FETCH_OP;
|
|
end
|
default: begin
|
default: begin
|
next_state = RESET;
|
next_state = RESET;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
Line 667... |
Line 730... |
write = 1'b0;
|
write = 1'b0;
|
jump = 1'b0;
|
jump = 1'b0;
|
jump_indirect = 1'b0;
|
jump_indirect = 1'b0;
|
branch = 1'b0;
|
branch = 1'b0;
|
|
|
|
break = 1'b0;
|
|
|
case (ir)
|
case (ir)
|
CLC_IMP, CLD_IMP, CLI_IMP, CLV_IMP, DEX_IMP, DEY_IMP, INX_IMP, INY_IMP, NOP_IMP, PHA_IMP, PHP_IMP, PLA_IMP,
|
CLC_IMP, CLD_IMP, CLI_IMP, CLV_IMP, DEX_IMP, DEY_IMP, INX_IMP, INY_IMP, NOP_IMP, PHA_IMP, PHP_IMP, PLA_IMP,
|
PLP_IMP, RTI_IMP, RTS_IMP, SEC_IMP, SED_IMP, SEI_IMP, TAX_IMP, TAY_IMP, TSX_IMP, TXA_IMP, TXS_IMP, TYA_IMP: begin
|
PLP_IMP, RTI_IMP, RTS_IMP, SEC_IMP, SED_IMP, SEI_IMP, TAX_IMP, TAY_IMP, TSX_IMP, TXA_IMP, TXS_IMP, TYA_IMP: begin
|
implied = 1'b1;
|
implied = 1'b1;
|
end
|
end
|
Line 808... |
Line 873... |
end
|
end
|
JMP_IND: begin
|
JMP_IND: begin
|
jump_indirect = 1'b1;
|
jump_indirect = 1'b1;
|
end
|
end
|
BRK_IMP: begin
|
BRK_IMP: begin
|
// something goes in here
|
break = 1'b1;
|
end
|
end
|
default: begin
|
default: begin
|
$write("state : %b", state);
|
$write("state : %b", state);
|
if (reset_n == 1 && state != FETCH_OP_FIX_PC) begin // the processor is NOT being reset neither it is fixing the pc
|
if (reset_n == 1 && state != FETCH_OP_FIX_PC) begin // the processor is NOT being reset neither it is fixing the pc
|
$write("\nunknown OPCODE!!!!! 0x%h\n", ir);
|
$write("\nunknown OPCODE!!!!! 0x%h\n", ir);
|