Line 29... |
Line 29... |
//
|
//
|
// *Author(s):
|
// *Author(s):
|
// - Olivier Girard, olgirard@gmail.com
|
// - Olivier Girard, olgirard@gmail.com
|
//
|
//
|
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
// $Rev: 105 $
|
// $Rev: 109 $
|
// $LastChangedBy: olivier.girard $
|
// $LastChangedBy: olivier.girard $
|
// $LastChangedDate: 2011-03-10 22:10:30 +0100 (Thu, 10 Mar 2011) $
|
// $LastChangedDate: 2011-03-27 13:49:47 +0200 (Sun, 27 Mar 2011) $
|
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
`ifdef OMSP_NO_INCLUDE
|
`ifdef OMSP_NO_INCLUDE
|
`else
|
`else
|
`include "openMSP430_defines.v"
|
`include "openMSP430_defines.v"
|
`endif
|
`endif
|
Line 66... |
Line 66... |
nmi_acc, // Non-Maskable interrupt request accepted
|
nmi_acc, // Non-Maskable interrupt request accepted
|
pc, // Program counter
|
pc, // Program counter
|
pc_nxt, // Next PC value (for CALL & IRQ)
|
pc_nxt, // Next PC value (for CALL & IRQ)
|
|
|
// INPUTs
|
// INPUTs
|
|
cpu_en_s, // Enable CPU code execution (synchronous)
|
cpuoff, // Turns off the CPU
|
cpuoff, // Turns off the CPU
|
dbg_halt_cmd, // Halt CPU command
|
dbg_halt_cmd, // Halt CPU command
|
dbg_reg_sel, // Debug selected register for rd/wr access
|
dbg_reg_sel, // Debug selected register for rd/wr access
|
fe_pmem_wait, // Frontend wait for Instruction fetch
|
fe_pmem_wait, // Frontend wait for Instruction fetch
|
gie, // General interrupt enable
|
gie, // General interrupt enable
|
Line 109... |
Line 110... |
output [15:0] pc; // Program counter
|
output [15:0] pc; // Program counter
|
output [15:0] pc_nxt; // Next PC value (for CALL & IRQ)
|
output [15:0] pc_nxt; // Next PC value (for CALL & IRQ)
|
|
|
// INPUTs
|
// INPUTs
|
//=========
|
//=========
|
|
input cpu_en_s; // Enable CPU code execution (synchronous)
|
input cpuoff; // Turns off the CPU
|
input cpuoff; // Turns off the CPU
|
input dbg_halt_cmd; // Halt CPU command
|
input dbg_halt_cmd; // Halt CPU command
|
input [3:0] dbg_reg_sel; // Debug selected register for rd/wr access
|
input [3:0] dbg_reg_sel; // Debug selected register for rd/wr access
|
input fe_pmem_wait; // Frontend wait for Instruction fetch
|
input fe_pmem_wait; // Frontend wait for Instruction fetch
|
input gie; // General interrupt enable
|
input gie; // General interrupt enable
|
Line 171... |
Line 173... |
parameter I_DEC = 3'h2; // New instruction ready for decode
|
parameter I_DEC = 3'h2; // New instruction ready for decode
|
parameter I_EXT1 = 3'h3; // 1st Extension word
|
parameter I_EXT1 = 3'h3; // 1st Extension word
|
parameter I_EXT2 = 3'h4; // 2nd Extension word
|
parameter I_EXT2 = 3'h4; // 2nd Extension word
|
parameter I_IDLE = 3'h5; // CPU is in IDLE mode
|
parameter I_IDLE = 3'h5; // CPU is in IDLE mode
|
|
|
|
// CPU on/off through the debug interface or cpu_en port
|
|
wire cpu_halt_cmd = dbg_halt_cmd | ~cpu_en_s;
|
|
|
// States Transitions
|
// States Transitions
|
always @(i_state or inst_sz or inst_sz_nxt or pc_sw_wr or exec_done or
|
always @(i_state or inst_sz or inst_sz_nxt or pc_sw_wr or exec_done or
|
exec_done or irq_detect or cpuoff or dbg_halt_cmd or e_state)
|
exec_done or irq_detect or cpuoff or cpu_halt_cmd or e_state)
|
case(i_state)
|
case(i_state)
|
I_IDLE : i_state_nxt = (irq_detect & ~dbg_halt_cmd) ? I_IRQ_FETCH :
|
I_IDLE : i_state_nxt = (irq_detect & ~cpu_halt_cmd) ? I_IRQ_FETCH :
|
(~cpuoff & ~dbg_halt_cmd) ? I_DEC : I_IDLE;
|
(~cpuoff & ~cpu_halt_cmd) ? I_DEC : I_IDLE;
|
I_IRQ_FETCH: i_state_nxt = I_IRQ_DONE;
|
I_IRQ_FETCH: i_state_nxt = I_IRQ_DONE;
|
I_IRQ_DONE : i_state_nxt = I_DEC;
|
I_IRQ_DONE : i_state_nxt = I_DEC;
|
I_DEC : i_state_nxt = irq_detect ? I_IRQ_FETCH :
|
I_DEC : i_state_nxt = irq_detect ? I_IRQ_FETCH :
|
(cpuoff | dbg_halt_cmd) & exec_done ? I_IDLE :
|
(cpuoff | cpu_halt_cmd) & exec_done ? I_IDLE :
|
dbg_halt_cmd & (e_state==`E_IDLE) ? I_IDLE :
|
cpu_halt_cmd & (e_state==`E_IDLE) ? I_IDLE :
|
pc_sw_wr ? I_DEC :
|
pc_sw_wr ? I_DEC :
|
~exec_done & ~(e_state==`E_IDLE) ? I_DEC : // Wait in decode state
|
~exec_done & ~(e_state==`E_IDLE) ? I_DEC : // Wait in decode state
|
(inst_sz_nxt!=2'b00) ? I_EXT1 : I_DEC; // until execution is completed
|
(inst_sz_nxt!=2'b00) ? I_EXT1 : I_DEC; // until execution is completed
|
I_EXT1 : i_state_nxt = irq_detect ? I_IRQ_FETCH :
|
I_EXT1 : i_state_nxt = irq_detect ? I_IRQ_FETCH :
|
pc_sw_wr ? I_DEC :
|
pc_sw_wr ? I_DEC :
|
Line 206... |
Line 211... |
|
|
// Debug interface cpu status
|
// Debug interface cpu status
|
reg dbg_halt_st;
|
reg dbg_halt_st;
|
always @(posedge mclk or posedge puc)
|
always @(posedge mclk or posedge puc)
|
if (puc) dbg_halt_st <= 1'b0;
|
if (puc) dbg_halt_st <= 1'b0;
|
else dbg_halt_st <= dbg_halt_cmd & (i_state_nxt==I_IDLE);
|
else dbg_halt_st <= cpu_halt_cmd & (i_state_nxt==I_IDLE);
|
|
|
|
|
//=============================================================================
|
//=============================================================================
|
// 2) INTERRUPT HANDLING
|
// 2) INTERRUPT HANDLING
|
//=============================================================================
|
//=============================================================================
|
Line 228... |
Line 233... |
always @(posedge mclk or posedge puc)
|
always @(posedge mclk or posedge puc)
|
if (puc) inst_irq_rst <= 1'b1;
|
if (puc) inst_irq_rst <= 1'b1;
|
else if (exec_done) inst_irq_rst <= 1'b0;
|
else if (exec_done) inst_irq_rst <= 1'b0;
|
|
|
// Detect other interrupts
|
// Detect other interrupts
|
assign irq_detect = (inst_nmi | ((|irq | wdt_irq) & gie)) & ~dbg_halt_cmd & ~dbg_halt_st & (exec_done | (i_state==I_IDLE));
|
assign irq_detect = (inst_nmi | ((|irq | wdt_irq) & gie)) & ~cpu_halt_cmd & ~dbg_halt_st & (exec_done | (i_state==I_IDLE));
|
|
|
// Select interrupt vector
|
// Select interrupt vector
|
reg [3:0] irq_num;
|
reg [3:0] irq_num;
|
always @(posedge mclk or posedge puc)
|
always @(posedge mclk or posedge puc)
|
if (puc) irq_num <= 4'hf;
|
if (puc) irq_num <= 4'hf;
|
Line 287... |
Line 292... |
if (puc) pmem_busy <= 1'b0;
|
if (puc) pmem_busy <= 1'b0;
|
else pmem_busy <= fe_pmem_wait;
|
else pmem_busy <= fe_pmem_wait;
|
|
|
// Memory interface
|
// Memory interface
|
wire [15:0] mab = pc_nxt;
|
wire [15:0] mab = pc_nxt;
|
wire mb_en = fetch | pc_sw_wr | (i_state==I_IRQ_FETCH) | pmem_busy | (dbg_halt_st & ~dbg_halt_cmd);
|
wire mb_en = fetch | pc_sw_wr | (i_state==I_IRQ_FETCH) | pmem_busy | (dbg_halt_st & ~cpu_halt_cmd);
|
|
|
|
|
//
|
//
|
// 3.2) INSTRUCTION REGISTER
|
// 3.2) INSTRUCTION REGISTER
|
//--------------------------------
|
//--------------------------------
|
Line 564... |
Line 569... |
1'b1 : inst_ad_nxt = 8'b01000000;
|
1'b1 : inst_ad_nxt = 8'b01000000;
|
default: inst_ad_nxt = 8'b00000001;
|
default: inst_ad_nxt = 8'b00000001;
|
endcase
|
endcase
|
else if (dest_reg==4'h0) // Addressing mode using R0
|
else if (dest_reg==4'h0) // Addressing mode using R0
|
case (ir[7])
|
case (ir[7])
|
2'b1 : inst_ad_nxt = 8'b00010000;
|
1'b1 : inst_ad_nxt = 8'b00010000;
|
default: inst_ad_nxt = 8'b00000001;
|
default: inst_ad_nxt = 8'b00000001;
|
endcase
|
endcase
|
else // General Addressing mode
|
else // General Addressing mode
|
case (ir[7])
|
case (ir[7])
|
2'b1 : inst_ad_nxt = 8'b00000010;
|
1'b1 : inst_ad_nxt = 8'b00000010;
|
default: inst_ad_nxt = 8'b00000001;
|
default: inst_ad_nxt = 8'b00000001;
|
endcase
|
endcase
|
end
|
end
|
|
|
reg [7:0] inst_ad;
|
reg [7:0] inst_ad;
|
Line 588... |
Line 593... |
|
|
// Operation size
|
// Operation size
|
reg inst_bw;
|
reg inst_bw;
|
always @(posedge mclk or posedge puc)
|
always @(posedge mclk or posedge puc)
|
if (puc) inst_bw <= 1'b0;
|
if (puc) inst_bw <= 1'b0;
|
else if (decode) inst_bw <= ir[6] & ~inst_type_nxt[`INST_JMP] & ~irq_detect & ~dbg_halt_cmd;
|
else if (decode) inst_bw <= ir[6] & ~inst_type_nxt[`INST_JMP] & ~irq_detect & ~cpu_halt_cmd;
|
|
|
// Extended instruction size
|
// Extended instruction size
|
assign inst_sz_nxt = {1'b0, (inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS] | inst_as_nxt[`IMM])} +
|
assign inst_sz_nxt = {1'b0, (inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS] | inst_as_nxt[`IMM])} +
|
{1'b0, ((inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]) & ~inst_type_nxt[`INST_SO])};
|
{1'b0, ((inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]) & ~inst_type_nxt[`INST_SO])};
|
always @(posedge mclk or posedge puc)
|
always @(posedge mclk or posedge puc)
|
Line 643... |
Line 648... |
if (puc) exec_dext_rdy <= 1'b0;
|
if (puc) exec_dext_rdy <= 1'b0;
|
else if (e_state==`E_DST_RD) exec_dext_rdy <= 1'b0;
|
else if (e_state==`E_DST_RD) exec_dext_rdy <= 1'b0;
|
else if (inst_dext_rdy) exec_dext_rdy <= 1'b1;
|
else if (inst_dext_rdy) exec_dext_rdy <= 1'b1;
|
|
|
// Execution first state
|
// Execution first state
|
//wire [3:0] e_first_state = dbg_halt_cmd ? `E_IDLE :
|
|
wire [3:0] e_first_state = ~dbg_halt_st & inst_so_nxt[`IRQ] ? `E_IRQ_0 :
|
wire [3:0] e_first_state = ~dbg_halt_st & inst_so_nxt[`IRQ] ? `E_IRQ_0 :
|
dbg_halt_cmd | (i_state==I_IDLE) ? `E_IDLE :
|
cpu_halt_cmd | (i_state==I_IDLE) ? `E_IDLE :
|
cpuoff ? `E_IDLE :
|
cpuoff ? `E_IDLE :
|
src_acalc_pre ? `E_SRC_AD :
|
src_acalc_pre ? `E_SRC_AD :
|
src_rd_pre ? `E_SRC_RD :
|
src_rd_pre ? `E_SRC_RD :
|
dst_acalc_pre ? `E_DST_AD :
|
dst_acalc_pre ? `E_DST_AD :
|
dst_rd_pre ? `E_DST_RD : `E_EXEC;
|
dst_rd_pre ? `E_DST_RD : `E_EXEC;
|