- added
git-svn-id: http://moon:8086/svn/vhdl/trunk@1425 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
|
||||
//
|
||||
// CLOCK DIVIDER
|
||||
//
|
||||
// UNcomment the below to use a
|
||||
// clock divider. This will allow a much
|
||||
// faster external clock to be used and still
|
||||
// slow down the internal core frequency.
|
||||
// USE the paramter N in PC.V to adjust the
|
||||
// frequency. Minimum N is 3.
|
||||
// COMMNET the below to use the external clock
|
||||
// directly as is. Note that the core will
|
||||
// always run at 1/4 the external clock.
|
||||
//
|
||||
//`define use_clock_divider
|
||||
|
||||
|
||||
//
|
||||
// DEBUG SIGNALS
|
||||
//
|
||||
// UNcomment the below to activate the
|
||||
// test bus for observability during debug
|
||||
//
|
||||
// `define show_debug_pins
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
/* PC.V
|
||||
**
|
||||
** This core adheres to GNU Public Licence
|
||||
** Jeung Joon Lee *** www.cmosexod.com
|
||||
** joon.lee@quantum.com
|
||||
**
|
||||
** JJL 12/12/98
|
||||
** updated 3/16/2000
|
||||
**
|
||||
** Highest module for the 8 bit general purpose microprocessor
|
||||
** Two submodules are declerared here, popcorn.v and sequencer.v
|
||||
** The role and functions of these modules are as following:
|
||||
** PC.V wrapper, and clock generator. Provides to the submodules
|
||||
** sys_clk and phase_1_clk
|
||||
** POPCORN.V The 8 bit datapath. Contains the ALU, register file,
|
||||
** the program counter, stack pointer and all of the muxes.
|
||||
** SEQUENCER.V The sequencer state machine. BAsed on the fetched opcode,
|
||||
** generates all of the sequence of control signals to
|
||||
** fetch more operands or finish executing the opcode.
|
||||
**
|
||||
*/
|
||||
|
||||
`include "inc.h"
|
||||
|
||||
module pc( sys_clk,
|
||||
sys_rst,
|
||||
addx_bus,
|
||||
data_bus,
|
||||
code_cs_l,
|
||||
code_rd_l,
|
||||
code_wr_l,
|
||||
sram_cs_l,
|
||||
slow_clk,
|
||||
port
|
||||
|
||||
`ifdef show_debug_pins
|
||||
,
|
||||
w_opl,
|
||||
w_pc,
|
||||
w_oplo,
|
||||
state,
|
||||
w_acc,
|
||||
w_ax,
|
||||
w_bx,
|
||||
w_p,
|
||||
w_ophi,
|
||||
w_flag,
|
||||
phase_1_clk,
|
||||
slow_clk4,
|
||||
reg_flag,
|
||||
tst_bus,
|
||||
reg_acc,
|
||||
reg_ax,
|
||||
reg_bx,
|
||||
reg_p,
|
||||
reg_opl
|
||||
`endif
|
||||
|
||||
);
|
||||
|
||||
|
||||
parameter N=6;
|
||||
|
||||
|
||||
input sys_clk;
|
||||
input sys_rst;
|
||||
inout [7:0] data_bus;
|
||||
inout [7:0] port;
|
||||
//input [1:0] tst_bus_sel;
|
||||
output [11:0] addx_bus;
|
||||
//output [7:0] tst_bus;
|
||||
output code_cs_l, code_rd_l, code_wr_l, sram_cs_l;
|
||||
output slow_clk;
|
||||
|
||||
`ifdef show_debug_pins
|
||||
// DEBUG SIGNALS
|
||||
output w_opl;
|
||||
output w_pc;
|
||||
output w_oplo;
|
||||
output [3:0] state;
|
||||
output w_acc;
|
||||
output w_ax;
|
||||
output w_bx;
|
||||
output w_p;
|
||||
output w_ophi;
|
||||
output w_flag;
|
||||
output phase_1_clk;
|
||||
output slow_clk4;
|
||||
output [2:0] reg_flag;
|
||||
output tst_bus;
|
||||
output [7:0] reg_acc;
|
||||
output [7:0] reg_ax;
|
||||
output [7:0] reg_bx;
|
||||
output [7:0] reg_p;
|
||||
output [7:0] reg_opl;
|
||||
`endif
|
||||
|
||||
wire w_acc,w_ax,w_bx,w_p,w_flag;
|
||||
wire pc_mux,w_pc,w_oplo,w_ophi,w_opl;
|
||||
wire slow_clk4;
|
||||
wire [2:0] bbus_mux;
|
||||
wire [3:0] alu_func;
|
||||
wire [2:0] reg_flag;
|
||||
wire [7:0] port;
|
||||
reg [1:0] state_slow_clk4;
|
||||
reg phase_1_clk;
|
||||
wire xx,slow_clk;
|
||||
wire [5:0] state;
|
||||
wire [7:0] b_bus,c_bus;
|
||||
wire [11:0] d_bus;
|
||||
wire [7:0] tst_bus;
|
||||
wire sp_mux, w_sp;
|
||||
wire [1:0] addx_mux;
|
||||
wire data_bus_wr;
|
||||
wire sram_cs_l, code_wr_l;
|
||||
wire flag_mux;
|
||||
wire [7:0] reg_acc;
|
||||
wire [7:0] reg_ax;
|
||||
wire [7:0] reg_bx;
|
||||
wire [7:0] reg_p;
|
||||
wire [7:0] reg_opl;
|
||||
//wire [7:0] port_in;
|
||||
//wire port_bus_ena;
|
||||
|
||||
// define test bus
|
||||
/*
|
||||
always @(tst_bus_sel or reg_opl or c_bus or b_bus or d_bus)
|
||||
case (tst_bus_sel)
|
||||
2'b00: tst_bus <= reg_opl;
|
||||
//2'b01: tst_bus <= b_bus;
|
||||
default: tst_bus <= b_bus;
|
||||
//2'b10: tst_bus <= c_bus;
|
||||
//default: tst_bus <= c_bus;
|
||||
//2'b11: tst_bus <= d_bus;
|
||||
endcase
|
||||
*/
|
||||
//assign tst_bus=tst_bus_sel[0] ? b_bus : c_bus;
|
||||
assign tst_bus=c_bus;
|
||||
|
||||
|
||||
`ifdef use_clock_divider
|
||||
//
|
||||
// CLOCK DIVIDER
|
||||
//
|
||||
//
|
||||
// N=5 sets for 1Mhz operation
|
||||
// N=7 sets for 250Khz op. good for slow speed debug
|
||||
reg [N-1:0] clk;
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst) clk <=0;
|
||||
else clk <= clk + 1;
|
||||
assign slow_clk = clk[N-1];
|
||||
assign slow_clk4 = ~clk[N-3];
|
||||
`else
|
||||
reg [1:0] clk;
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst) clk <= 2'b00;
|
||||
else clk <= clk + 1;
|
||||
assign slow_clk = clk[1];
|
||||
assign slow_clk4 = sys_clk;
|
||||
`endif
|
||||
|
||||
/* define phase_1 clock
|
||||
** | |
|
||||
** | ___ ___ ___ ___ | ___ ___
|
||||
** slow_clk*4 |/ \___/ \___/ \___/ \___|/ \___/ \___
|
||||
** | _______ _______ | _______
|
||||
** slow_clk*2 |/ \_______/ \_______|/ \_______
|
||||
** | _______________ | _______________
|
||||
** slow_clk |/ \_______________|/
|
||||
** |________ _______|_
|
||||
** phase_1 | \_______________/ |
|
||||
** | |
|
||||
*/
|
||||
always @(posedge slow_clk4 or negedge sys_rst)
|
||||
if (~sys_rst) begin
|
||||
state_slow_clk4<=2'b00;
|
||||
phase_1_clk<=1'b1;
|
||||
end
|
||||
else case (state_slow_clk4)
|
||||
2'b00: begin state_slow_clk4<=2'b01; phase_1_clk<=1'b1; end
|
||||
2'b01: begin state_slow_clk4<=2'b11; phase_1_clk<=1'b1; end
|
||||
2'b11: begin state_slow_clk4<=2'b10; phase_1_clk<=1'b0; end
|
||||
2'b10: begin state_slow_clk4<=2'b00; phase_1_clk<=1'b0; end
|
||||
endcase
|
||||
|
||||
// instantiate the datapath
|
||||
popcorn POPCORN( .sys_clk(slow_clk),
|
||||
.sys_rst(sys_rst),
|
||||
.w_acc(w_acc),
|
||||
.w_ax(w_ax),
|
||||
.w_bx(w_bx),
|
||||
.w_p(w_p),
|
||||
.w_flag(w_flag),
|
||||
.bbus_mux(bbus_mux),
|
||||
.alu_func(alu_func),
|
||||
.pc_mux(pc_mux),
|
||||
.sp_mux(sp_mux),
|
||||
.flag_mux(flag_mux),
|
||||
.addx_mux(addx_mux),
|
||||
.w_pc(w_pc),
|
||||
.w_sp(w_sp),
|
||||
.w_oplo(w_oplo),
|
||||
.w_ophi(w_ophi),
|
||||
.w_opl(w_opl),
|
||||
.data_bus(data_bus),
|
||||
.port(port),
|
||||
// .port_in(port_in),
|
||||
.addx_bus(addx_bus),
|
||||
.reg_opl(reg_opl),
|
||||
.reg_flag(reg_flag),
|
||||
.b_bus(b_bus),
|
||||
.c_bus(c_bus),
|
||||
.d_bus(d_bus),
|
||||
.data_bus_wr(data_bus_wr),
|
||||
.code_wr_l(code_wr_l),
|
||||
.reg_acc(reg_acc),
|
||||
.reg_ax(reg_ax),
|
||||
.reg_bx(reg_bx),
|
||||
.reg_p(reg_p)
|
||||
);
|
||||
|
||||
// instantiate the sequencer
|
||||
sequencer SEQ ( .sys_clk(slow_clk),
|
||||
.phase_1_clk(phase_1_clk),
|
||||
.sys_rst(sys_rst),
|
||||
.w_acc(w_acc),
|
||||
.w_ax(w_ax),
|
||||
.w_bx(w_bx),
|
||||
.w_p(w_p),
|
||||
.w_flag(w_flag),
|
||||
.bbus_mux(bbus_mux),
|
||||
.alu_func(alu_func),
|
||||
.pc_mux(pc_mux),
|
||||
.addx_mux(addx_mux),
|
||||
.sp_mux(sp_mux),
|
||||
.flag_mux(flag_mux),
|
||||
.w_pc(w_pc),
|
||||
.w_sp(w_sp),
|
||||
.w_oplo(w_oplo),
|
||||
.w_ophi(w_ophi),
|
||||
.w_opl(w_opl),
|
||||
.reg_opl(reg_opl),
|
||||
.code_cs_l(code_cs_l),
|
||||
.code_rd_l(code_rd_l),
|
||||
.code_wr_l(code_wr_l),
|
||||
.sram_cs_l(sram_cs_l),
|
||||
.reg_flag(reg_flag),
|
||||
.data_bus_wr(data_bus_wr),
|
||||
.next_state(state)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Note on pin assignment:
|
||||
** o use pin file : "finalpin.pin"
|
||||
** o use global clock Y0 for 66Mhz source
|
||||
** o use global reset for reset.
|
||||
** o use N=6. This requires 64Mhz to give internal clock speed of 1Mhz.
|
||||
**
|
||||
** 2/12/99
|
||||
** o Fixed the LDM ACC,xx bug. ALU was not being set for c_bus = b_bus.
|
||||
** Call this 'popcorn - final'
|
||||
**
|
||||
** 2/11/99
|
||||
** o Uncovered and fixed 2 bugs relating the IO PORT:
|
||||
** 1.The signals 'reg_port_gate' which controls the gate of the port
|
||||
** output buffer has the wrong polarity. This was causing the port
|
||||
** to drive the port IO pin only when it was being read.
|
||||
** 2.The state of the bbus_mux[2:0] during LDACC/STADD was set to unknown.
|
||||
** This was causing the reg_port_gate to be deasserted during LDACC PORT
|
||||
** or STACC PORT instructions for 1 cycle, causing glitches in the IO port
|
||||
** pin
|
||||
**
|
||||
** 1/8/99
|
||||
** o Succesfully ran a timer program which toggles all bits of the
|
||||
** port register at 2mS interval (period=4mS). The program uses
|
||||
** an instrunctions timed 2mS delay subroutine.
|
||||
**
|
||||
** 1/7/99
|
||||
** o Somewhat final version. The test bus (TST[7:0]) has been dropped
|
||||
** and PORT[7:0] been used. All instructions works at least at 2 Mhz.
|
||||
** Call this 'popcorn -v5'
|
||||
**
|
||||
** 1/5/99
|
||||
** o Droppped the automatic pushing and popping of the flags when CALL/RET
|
||||
** are executed, (could not fit). So reduced the size of REG_OPHI down
|
||||
** to 4 from 8 bits. Instead the pushing of the flag is now done with
|
||||
** LDACC flag
|
||||
** LDM flag, #addx
|
||||
** PUSH flag
|
||||
** POP flag
|
||||
** instructions. The flag register still is muxed from ALU and c_bus.
|
||||
** Thanks Lord.
|
||||
** All that remains now is implementation of interrupt support.
|
||||
**
|
||||
** 1/3/99
|
||||
** o Removed DX and CX register from the register file, to free-up
|
||||
** the b_mux. The freed b_bus mux inputs are used by the PC (hi and low).
|
||||
** This allows PC to be pushed into the stack as well as CALL and RET
|
||||
** and push flag instructions
|
||||
**
|
||||
** 1/1/99
|
||||
** o Removed 7 level-deep hardware stack - it was obvious that this is not
|
||||
** a very robust way of having a stack. It limits the CALL/RET depth.
|
||||
** However my initial rational for not implementing the SP was that I
|
||||
** did not wanted to have a SRAM for stack. SRAM automatically implies
|
||||
** an extenal IC (since on FPGA you could not provide the required
|
||||
** amount of space).
|
||||
** o Added another addressing mode: direct mode, and 2 instructions: LDM and
|
||||
** STM (load mem, store mem). This brings the modes
|
||||
** to: register direct, immediate and direct.
|
||||
** Why not, I had decided to have exnal SRAM, so let's make use of it
|
||||
**
|
||||
** 12/28/98
|
||||
** o Added 7-level deep hardware LIFO to implement pushacc/popacc
|
||||
** instructions
|
||||
** o Implemented pushacc and popacc instructions in the sequencer.v
|
||||
**
|
||||
** 12/27/98
|
||||
** o Fixed a number of bugs, including CMPACC (reg direct) and ALU ops (reg
|
||||
** direct) being decoded as same.
|
||||
**
|
||||
** 12/26/98
|
||||
** o Shortenend the PC to 12 bits from 16, to reduce design size.
|
||||
** o REduced the datapath width to 8 from 16, to reduce design size.
|
||||
**
|
||||
** Lots of previous history not accounted for. Started to work on POPCORN
|
||||
** about 12/12/98
|
||||
*/
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
** POPCORN
|
||||
**
|
||||
** This core adheres to GNU Public Licence
|
||||
** Jeung Joon Lee *** www.cmosexod.com
|
||||
** joon.lee@quantum.com
|
||||
**
|
||||
** JJL 12/12/98
|
||||
** updated 3/16/2000
|
||||
**
|
||||
** This is an 8 bit general purpose microprocessor. The architecture
|
||||
** is that of a CISC type with accumulator-based operations.
|
||||
** The internal data-path is 8 bits, and the external bus is 8.
|
||||
** No support for muliply or other complex arithmetic operations are
|
||||
** supported (see ALU below).
|
||||
**
|
||||
** Two addressing modes: immediate and register-direct.f
|
||||
** 23 instructions are supported
|
||||
**
|
||||
** Instrutions lengths can be 1 or 2 or 3 bytes, which correcponds to
|
||||
** executions times of 2, 3 and 4 cycles.
|
||||
|
||||
** to change the address width: from 12 bits to wider:
|
||||
** change:
|
||||
** AW to desired value (all 3 files)
|
||||
** REG_OPHI width definition
|
||||
**
|
||||
*/
|
||||
|
||||
module popcorn( sys_clk, // system clock 1Mhz
|
||||
sys_rst, // system reset active low
|
||||
w_acc, // accumulator write signal, active low
|
||||
w_ax, // AX regster write signal, active low
|
||||
w_bx, // BX " " "
|
||||
w_p, // PORT " " "
|
||||
w_flag, // FLAG " " "
|
||||
bbus_mux, // bbus mux selector
|
||||
alu_func,
|
||||
pc_mux,
|
||||
addx_mux,
|
||||
sp_mux,
|
||||
flag_mux,
|
||||
w_pc,
|
||||
w_sp,
|
||||
w_oplo,
|
||||
w_ophi,
|
||||
w_opl,
|
||||
data_bus,
|
||||
addx_bus,
|
||||
port,
|
||||
reg_opl,
|
||||
reg_flag,
|
||||
|
||||
c_bus,
|
||||
b_bus,
|
||||
d_bus,
|
||||
data_bus_wr,
|
||||
code_wr_l,
|
||||
reg_acc,
|
||||
reg_ax,
|
||||
reg_bx,
|
||||
reg_p
|
||||
);
|
||||
|
||||
input sys_clk,sys_rst,w_acc,w_ax,w_bx,w_p,w_flag;
|
||||
input pc_mux,w_pc,w_oplo,w_ophi,w_opl;
|
||||
input [3:0] alu_func;
|
||||
input [2:0] bbus_mux;
|
||||
input data_bus_wr;
|
||||
input code_wr_l;
|
||||
output [7:0] b_bus,c_bus;
|
||||
output [11:0] d_bus;
|
||||
output [7:0] reg_opl;
|
||||
output [2:0] reg_flag;
|
||||
inout [7:0] data_bus;
|
||||
inout [7:0] port;
|
||||
output [11:0] addx_bus;
|
||||
input sp_mux,w_sp;
|
||||
input [1:0] addx_mux;
|
||||
input flag_mux;
|
||||
output [7:0] reg_acc;
|
||||
output [7:0] reg_ax;
|
||||
output [7:0] reg_bx;
|
||||
output [7:0] reg_p;
|
||||
|
||||
reg [7:0] reg_ax,reg_bx,reg_acc;
|
||||
reg [11:0] reg_pc, reg_sp;
|
||||
reg [7:0] reg_opl,reg_oplo,reg_p;
|
||||
reg [3:0] reg_ophi;
|
||||
reg carry,pos,zero,cout;
|
||||
reg [7:0] b_bus,c_bus;
|
||||
reg [11:0] addx_bus;
|
||||
//reg [7:0] reg_port_dir;
|
||||
wire [2:0] reg_flag;
|
||||
wire [11:0] d_bus;
|
||||
wire [7:0] data;
|
||||
wire [7:0] input_port;
|
||||
wire cs_reg_port_dir;
|
||||
wire reg_port_gate;
|
||||
|
||||
/*
|
||||
** DATA BUS :: bi-directional
|
||||
** Output c_bus onto the pad at data_bus_wr == 0
|
||||
*/
|
||||
assign data = data_bus; // input
|
||||
assign data_bus = data_bus_wr ? 8'hzz : c_bus; //output
|
||||
|
||||
/*
|
||||
** REGISTER FILE :: Synchronous to sys_clk
|
||||
** There are total of 6 registers
|
||||
** ACC accumulator 8 bit
|
||||
** AX general purpose register 8 bit
|
||||
** BX general purpose register 8 bit
|
||||
** P I/O port register 4 bit
|
||||
*/
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_p <= 8'h00;
|
||||
else if(~w_p)
|
||||
reg_p <= c_bus;
|
||||
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_ax <= 8'h00;
|
||||
else if(~w_ax)
|
||||
reg_ax <= c_bus;
|
||||
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_bx <= 8'h00;
|
||||
else if(~w_bx)
|
||||
reg_bx <= c_bus;
|
||||
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_acc <= 8'h00;
|
||||
else if(~w_acc)
|
||||
reg_acc <= c_bus;
|
||||
|
||||
|
||||
/* OPL :: Synchronous to W_OPL
|
||||
** Opcode_Latch register 8 bit
|
||||
** Latched by rising edge of W_OPL
|
||||
*/
|
||||
always @(posedge w_opl or negedge sys_rst)
|
||||
if(~sys_rst)
|
||||
reg_opl <= 8'h00;
|
||||
else
|
||||
reg_opl <= data;
|
||||
|
||||
/*
|
||||
** PC:: Synchronous to sys_clk
|
||||
** Program Counter 8 bit
|
||||
**
|
||||
** Input: sys_clk : on rising edge, PC is update
|
||||
** w_pc : 1=allow pc to change, 0=pc has its previous
|
||||
** value
|
||||
** pc_mux : 1=on the rising edge of sys_clk pc=pc+1
|
||||
** 0=on the rising edge of sys_clk pc=d_bus
|
||||
*/
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_pc <= 12'h000; // the reset value must be all 0's
|
||||
else if (~w_pc & pc_mux)
|
||||
reg_pc <= reg_pc + 1;
|
||||
else if ( ~w_pc & ~pc_mux )
|
||||
reg_pc <= d_bus;
|
||||
else
|
||||
reg_pc <= reg_pc;
|
||||
|
||||
/*
|
||||
** SP :: Synchrnous to sys_clk
|
||||
** Stack Pointer
|
||||
*/
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_sp <= 12'hFFF; // default reset value of sp is 0xFFF
|
||||
else if (~w_sp & sp_mux)
|
||||
reg_sp <= reg_sp - 1;
|
||||
else if ( ~w_sp & ~sp_mux)
|
||||
reg_sp <= reg_sp + 1;
|
||||
|
||||
/*
|
||||
** ADDX mux
|
||||
*/
|
||||
always @(addx_mux or reg_pc or reg_sp or d_bus)
|
||||
case (addx_mux)
|
||||
2'b00: addx_bus <= d_bus;
|
||||
2'b01: addx_bus <= reg_pc;
|
||||
default: addx_bus <= reg_sp;
|
||||
endcase
|
||||
|
||||
/*
|
||||
** Arithmetic Logic Unit
|
||||
** This ALU provides 9 funtions:
|
||||
** 0 c = a+b
|
||||
** 1 c = a-b (a+~b+1)
|
||||
** 2 c = a&b
|
||||
** 3 c = a|b
|
||||
** 4 c = a^b
|
||||
** 5 c = ~a
|
||||
** 6 c = a >> 1
|
||||
** 7 c = a << 1
|
||||
** 8 c = b
|
||||
** else c = a
|
||||
*/
|
||||
always @(reg_acc or b_bus or alu_func) begin
|
||||
case (alu_func)
|
||||
4'b0000: {cout,c_bus} <= reg_acc+b_bus;
|
||||
4'b0001: {cout,c_bus} <= reg_acc-b_bus;
|
||||
4'b0010: begin c_bus <= reg_acc&b_bus; cout<=1'b0; end
|
||||
4'b0011: begin c_bus <= reg_acc|b_bus; cout<=1'b0; end
|
||||
4'b0100: begin c_bus <= reg_acc^b_bus; cout<=1'b0; end
|
||||
4'b0101: begin c_bus <= ~reg_acc; cout<=1'b0; end
|
||||
4'b0110: begin c_bus <= {1'b0,reg_acc[7:1]}; cout<=reg_acc[0]; end
|
||||
4'b0111: begin c_bus <= {reg_acc[6:0],1'b0}; cout<=reg_acc[7]; end
|
||||
4'b1000: begin c_bus <= b_bus; cout<=1'b0; end
|
||||
default: begin c_bus <= reg_acc; cout<=1'b0; end
|
||||
endcase
|
||||
end
|
||||
|
||||
// Define ALU flag register
|
||||
always @(posedge sys_clk or negedge sys_rst)
|
||||
if (~sys_rst) begin
|
||||
pos <= 1'b0;
|
||||
zero <= 1'b0;
|
||||
carry <= 1'b0;
|
||||
end
|
||||
else if ((~w_flag) && (flag_mux==1'b1)) begin
|
||||
zero <= ~( | c_bus ); // zero=1 iff all bits==0
|
||||
pos <= ~(c_bus[7]); // pos=1 iff msb=0
|
||||
carry <= cout; // carry , see alu above
|
||||
end
|
||||
else if ((~w_flag) && (flag_mux==1'b0)) begin
|
||||
zero <= c_bus[5]; // zero=1 iff all bits==0
|
||||
pos <= c_bus[6]; // pos=1 iff msb=0
|
||||
carry <= c_bus[7]; // carry , see alu above
|
||||
end
|
||||
|
||||
assign reg_flag = {carry,pos,zero};
|
||||
|
||||
/*
|
||||
** Define B MUX
|
||||
*/
|
||||
always @(reg_ax or reg_bx or reg_flag or reg_pc or d_bus or reg_p or bbus_mux or input_port)
|
||||
case (bbus_mux)
|
||||
3'b001: b_bus <= reg_ax;
|
||||
3'b010: b_bus <= reg_bx;
|
||||
3'b011: b_bus <= reg_pc[7:0];
|
||||
3'b100: b_bus <= {reg_flag,1'b0,reg_pc[11:8]};
|
||||
3'b101: b_bus <= input_port;
|
||||
3'b110: b_bus <= d_bus[7:0];
|
||||
default: b_bus <=d_bus;
|
||||
endcase
|
||||
|
||||
|
||||
/*
|
||||
** Define d_bus
|
||||
*/
|
||||
assign d_bus={reg_ophi[3:0],reg_oplo};
|
||||
always @(posedge w_oplo or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_oplo <= 8'h00;
|
||||
else
|
||||
reg_oplo <= data;
|
||||
always @(posedge w_ophi or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_ophi <= 4'b0000;
|
||||
else
|
||||
reg_ophi <= data[3:0];
|
||||
|
||||
|
||||
/*
|
||||
** Define the PORT register :: Synchronous to sys_clk
|
||||
*/
|
||||
/*
|
||||
assign port[0] = reg_port_dir[0] ? 1'bz : reg_p[0];
|
||||
assign port[1] = reg_port_dir[1] ? 1'bz : reg_p[1];
|
||||
assign port[2] = reg_port_dir[2] ? 1'bz : reg_p[2];
|
||||
assign port[3] = reg_port_dir[3] ? 1'bz : reg_p[3];
|
||||
assign port[4] = reg_port_dir[4] ? 1'bz : reg_p[4];
|
||||
assign port[5] = reg_port_dir[5] ? 1'bz : reg_p[5];
|
||||
assign port[6] = reg_port_dir[6] ? 1'bz : reg_p[6];
|
||||
assign port[7] = reg_port_dir[7] ? 1'bz : reg_p[7];
|
||||
*/
|
||||
|
||||
assign input_port = port;
|
||||
//assign port = reg_port_gate ? 8'hzz : reg_p;
|
||||
|
||||
bufif1(port[0], reg_p[0], reg_port_gate);
|
||||
bufif1(port[1], reg_p[1], reg_port_gate);
|
||||
bufif1(port[2], reg_p[2], reg_port_gate);
|
||||
bufif1(port[3], reg_p[3], reg_port_gate);
|
||||
bufif1(port[4], reg_p[4], reg_port_gate);
|
||||
bufif1(port[5], reg_p[5], reg_port_gate);
|
||||
bufif1(port[6], reg_p[6], reg_port_gate);
|
||||
bufif1(port[7], reg_p[7], reg_port_gate);
|
||||
|
||||
assign reg_port_gate = (bbus_mux[2:0]==3'b101);
|
||||
|
||||
/*
|
||||
assign cs_reg_port_dir = ( ~(addx_bus==12'hD00) | (~code_wr_l) );
|
||||
always @(posedge cs_reg_port_dir or negedge sys_rst)
|
||||
if (~sys_rst)
|
||||
reg_port_dir <= 8'h00;
|
||||
else
|
||||
reg_port_dir <= c_bus;
|
||||
*/
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
** SEQUENCER
|
||||
**
|
||||
** This core adheres to GNU Public Licence
|
||||
** Jeung Joon Lee *** www.cmosexod.com
|
||||
** joon.lee@quantum.com
|
||||
**
|
||||
** JJL 12/12/98
|
||||
** updated 3/16/2000
|
||||
**
|
||||
**
|
||||
** This is the sequencer for the POPCORN 8bit microprocessor.
|
||||
** Controls all of the control signals.
|
||||
**
|
||||
** This sequencer controls these following signals of the datapath "popcorn"
|
||||
**
|
||||
**
|
||||
**
|
||||
*/
|
||||
module sequencer (sys_clk,
|
||||
phase_1_clk,
|
||||
sys_rst,
|
||||
w_acc,
|
||||
w_ax,
|
||||
w_bx,
|
||||
w_p,
|
||||
w_flag,
|
||||
bbus_mux,
|
||||
alu_func,
|
||||
pc_mux,
|
||||
addx_mux,
|
||||
sp_mux,
|
||||
flag_mux,
|
||||
w_sp,
|
||||
w_pc,
|
||||
w_oplo,
|
||||
w_ophi,
|
||||
w_opl,
|
||||
reg_opl,
|
||||
code_cs_l,
|
||||
code_rd_l,
|
||||
sram_cs_l,
|
||||
code_wr_l,
|
||||
reg_flag,
|
||||
data_bus_wr,
|
||||
next_state
|
||||
);
|
||||
|
||||
input sys_clk,sys_rst,phase_1_clk;
|
||||
input [7:0] reg_opl;
|
||||
input [2:0] reg_flag;
|
||||
output w_acc,w_ax,w_bx,w_p,w_flag,pc_mux,w_pc;
|
||||
output w_opl,w_oplo,w_ophi,code_cs_l,code_rd_l;
|
||||
output [3:0] alu_func;
|
||||
output [2:0] bbus_mux;
|
||||
output [3:0] next_state;
|
||||
output [1:0] addx_mux;
|
||||
output sp_mux, w_sp, sram_cs_l, code_wr_l, data_bus_wr;
|
||||
output flag_mux;
|
||||
|
||||
reg [5:0] next_state;
|
||||
reg code_cs_l,code_rd_l_gate;
|
||||
reg w_opl_gate,w_acc_gate,w_ax_gate,w_bx_gate;
|
||||
reg w_p_gate,w_flag_gate,pc_mux;
|
||||
reg w_oplo_gate,w_ophi_gate,w_pc_gate;
|
||||
reg [3:0] alu_func;
|
||||
reg [2:0] bbus_mux;
|
||||
reg dummy;
|
||||
reg [1:0] addx_mux;
|
||||
reg w_sp_gate, sp_mux, sram_cs_l, code_wr_l_gate,data_bus_wr;
|
||||
reg flag_mux;
|
||||
|
||||
parameter state_s0 =6'b000001;
|
||||
parameter state_s1 =6'b000010;
|
||||
parameter state_s2 =6'b000100;
|
||||
parameter state_s3 =6'b001000;
|
||||
parameter state_s4 =6'b010000;
|
||||
parameter state_s5 =6'b100000;
|
||||
|
||||
assign w_acc = w_acc_gate;
|
||||
assign w_ax = w_ax_gate;
|
||||
assign w_bx = w_bx_gate;
|
||||
assign w_p = w_p_gate;
|
||||
assign w_flag= w_flag_gate;
|
||||
assign w_pc = w_pc_gate;
|
||||
assign w_sp = w_sp_gate;
|
||||
assign w_oplo= w_oplo_gate | phase_1_clk; // asynchronous reg
|
||||
assign w_ophi= w_ophi_gate | phase_1_clk; // asynchronous reg
|
||||
assign w_opl = w_opl_gate | phase_1_clk; // asynchronous reg
|
||||
assign code_rd_l = code_rd_l_gate | phase_1_clk; // code rom rd
|
||||
assign code_wr_l = code_wr_l_gate | phase_1_clk;
|
||||
|
||||
/*
|
||||
** Behavioral description of the Sequencer State machine
|
||||
**
|
||||
** synchronous state machine, transitions on the rising edge of sys_clk
|
||||
*/
|
||||
always @(posedge sys_clk or negedge sys_rst) begin
|
||||
if (~sys_rst) begin // rst
|
||||
code_cs_l <= 1'b1;
|
||||
code_rd_l_gate <= 1'b1;
|
||||
code_wr_l_gate <= 1'b1;
|
||||
sram_cs_l <= 1'b1;
|
||||
alu_func <= 4'b0000;
|
||||
w_acc_gate <= 1'b1;
|
||||
w_ax_gate <= 1'b1;
|
||||
w_bx_gate <= 1'b1;
|
||||
w_p_gate <= 1'b1;
|
||||
w_flag_gate <= 1'b1;
|
||||
w_opl_gate <= 1'b1;
|
||||
w_oplo_gate <= 1'b1;
|
||||
w_ophi_gate <= 1'b1;
|
||||
bbus_mux <= 2'b00;
|
||||
addx_mux <= 2'b01;
|
||||
pc_mux <= 1'b1;
|
||||
sp_mux <= 1'b1;
|
||||
flag_mux <= 1'b1;
|
||||
w_pc_gate <= 1'b1;
|
||||
w_sp_gate <= 1'b1;
|
||||
data_bus_wr <= 1'b1;
|
||||
// port_bus_ena <= 1'b0;
|
||||
next_state <= state_s0;
|
||||
end
|
||||
else case(next_state)
|
||||
/*
|
||||
** FETCH OPCODE STATE. (at beginning of s1 opcode is latched into reg_opl)
|
||||
*/
|
||||
state_s0: begin // *****2
|
||||
code_cs_l <= 1'b0; // enable code cs
|
||||
code_rd_l_gate <= 1'b0; // enable code rd
|
||||
code_wr_l_gate <= 1'b1;
|
||||
sram_cs_l <= 1'b1;
|
||||
alu_func <= 4'bx;
|
||||
w_acc_gate <= 1'b1;
|
||||
w_ax_gate <= 1'b1;
|
||||
w_bx_gate <= 1'b1;
|
||||
w_p_gate <= 1'b1;
|
||||
w_flag_gate <= 1'b1;
|
||||
w_opl_gate <= 1'b0; // latch opl at s1
|
||||
w_oplo_gate <= 1'b1;
|
||||
w_ophi_gate <= 1'b1;
|
||||
bbus_mux <= 2'b00;
|
||||
addx_mux <= 2'b01;
|
||||
pc_mux <= 1'b1;
|
||||
sp_mux <= 1'b1;
|
||||
flag_mux <= 1'b1;
|
||||
w_pc_gate <= 1'b1;
|
||||
w_sp_gate <= 1'b1;
|
||||
data_bus_wr <= 1'b1;
|
||||
//port_bus_ena <= 1'b0;
|
||||
next_state <= state_s1;
|
||||
end
|
||||
/*
|
||||
** REGISTER DIRECT INSTRUCTIONS 1 byte, 2 cycle instructions
|
||||
** these are: stacc, ldacc, and alu ops
|
||||
*/
|
||||
state_s1: begin // ******** 2
|
||||
|
||||
begin
|
||||
code_cs_l <= 1'b1; // disable cs and rd from code ram
|
||||
code_rd_l_gate <= 1'b1;
|
||||
w_opl_gate <= 1'b1; // disable opcode latch gate
|
||||
end
|
||||
|
||||
// ALU opcode - register direct
|
||||
if((reg_opl[7:6]==2'b00)&&(reg_opl[2:0]!=3'b111)) begin
|
||||
alu_func <= reg_opl[6:3];
|
||||
w_acc_gate <= 1'b0; // latch acc with result on s0
|
||||
w_flag_gate <= 1'b0; // latch reg result on s0
|
||||
bbus_mux <= reg_opl[2:0];
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// CMPACC opcode - register direct
|
||||
else if((reg_opl[7:3]==5'b01000)&&(reg_opl[2:0]!=3'b111)) begin
|
||||
alu_func <= 4'b0001; // alu subtract
|
||||
w_flag_gate <= 1'b0; // latch reg result on s0
|
||||
bbus_mux <= reg_opl[2:0];
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// LDACC - register direct
|
||||
else if ((reg_opl[7:3]==5'b10001)&&(reg_opl[2:0]!=3'b111)) begin
|
||||
alu_func <= 4'b1000; // alu=select b bus
|
||||
w_acc_gate <= 1'b0; // latch acc on s0
|
||||
bbus_mux <= reg_opl[2:0];
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// STACC - register direct
|
||||
else if ((reg_opl[7:3]==5'b10010)&&(reg_opl[2:0]!=3'b111)) begin
|
||||
alu_func <= 4'b1001; // alu=select a bus
|
||||
case (reg_opl[2:0]) // latch approp dest reg on s0
|
||||
3'b001: w_ax_gate <= 1'b0;
|
||||
3'b010: w_bx_gate <= 1'b0;
|
||||
3'b100: begin
|
||||
w_flag_gate <= 1'b0;
|
||||
flag_mux <= 1'b0;
|
||||
end
|
||||
3'b101: w_p_gate <= 1'b0;
|
||||
default: dummy <= 1'b0; // do nothing
|
||||
endcase
|
||||
bbus_mux <= 3'b001; // anything but 3'b101 (port)
|
||||
w_pc_gate <= 1'b0; // increment pc in s0
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// PUSH , write out to [SP] and decrement SP
|
||||
// push does this: [SP] <- reg, SP=SP-1
|
||||
else if(reg_opl[7:3]==5'b01110) begin
|
||||
if (reg_opl[2:0]==3'b000) begin
|
||||
alu_func <= 4'b1001; // select c_bus=acc
|
||||
end else begin
|
||||
alu_func <= 4'b1000; // select c_bus=b_bus
|
||||
end
|
||||
bbus_mux <= reg_opl[2:0];
|
||||
sp_mux <= 1'b1; // sp = sp -1
|
||||
w_sp_gate <= 1'b0; // allow sp to decrement
|
||||
addx_mux <= 2'b10; // select sp as addx source
|
||||
sram_cs_l <= 1'b0; // select sram
|
||||
code_wr_l_gate <= 1'b0; // and write
|
||||
data_bus_wr <= 1'b0; // drive data bus with c_bus
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// POP, RET part I, increment SP
|
||||
// pop does this:
|
||||
// SP=SP+1
|
||||
// reg_ophi <- [SP]
|
||||
// SP=SP+1
|
||||
// reg_oplo <- [SP]
|
||||
else if (reg_opl[7:3]==5'b01111 | reg_opl[7:0]==8'b11011110) begin
|
||||
alu_func <= 4'b1000; // c_bus = b_bus
|
||||
bbus_mux <= 3'b110; // b_bus = d_bus
|
||||
sp_mux <= 1'b0; // sp = sp + 1
|
||||
w_sp_gate <= 1'b0; // allow sp to increment
|
||||
next_state <= state_s2;
|
||||
end
|
||||
|
||||
// Immediate mode, so need to go and fetch one or two operands.
|
||||
// setup the PC so it increments to 1 and cs and rd gates
|
||||
// are asserted
|
||||
else begin
|
||||
alu_func <= 4'b1000;
|
||||
w_acc_gate <= 1'b1;
|
||||
w_ax_gate <= 1'b1;
|
||||
w_bx_gate <= 1'b1;
|
||||
w_p_gate <= 1'b1;
|
||||
w_oplo_gate <= 1'b1;
|
||||
bbus_mux <= 3'b110; // show d_bus on c_bus
|
||||
pc_mux <= 1'b1;
|
||||
w_pc_gate <= 1'b0; // increment pc on s2
|
||||
next_state <= state_s2;
|
||||
end
|
||||
end
|
||||
|
||||
/*
|
||||
** IMMEDIATE INSTRUCTIONS. 2 bytes, 3 cycle insruction
|
||||
** these are: ldi, alu ops.
|
||||
*/
|
||||
state_s2: begin
|
||||
// LDI - load immediate 8 bit value to register
|
||||
if ((reg_opl[7:6]==2'b10)&&(reg_opl[2:0]==3'b111)) begin
|
||||
alu_func <= 4'b1000;
|
||||
case (reg_opl[5:3]) // latch the dest reg on s0
|
||||
3'b000: w_acc_gate <= 1'b0;
|
||||
3'b001: w_ax_gate <= 1'b0;
|
||||
3'b010: w_bx_gate <= 1'b0;
|
||||
3'b101: w_p_gate <= 1'b0;
|
||||
default: dummy <= 1'b0; //do nothing
|
||||
endcase
|
||||
bbus_mux <= 3'b110;
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
code_cs_l <= 1'b0; // allow -cs and -rd to code ram
|
||||
code_rd_l_gate <= 1'b0;
|
||||
w_oplo_gate <= 1'b0; // assert oplo gate
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// ALU op - immediate
|
||||
else if ((reg_opl[7:6]==2'b00)&&(reg_opl[2:0]==3'b111)) begin
|
||||
alu_func <= reg_opl[6:3]; // get alu oprerationg from instruction
|
||||
w_acc_gate <= 1'b0; // latch acc on s0
|
||||
w_flag_gate <= 1'b0; // update flag on s0
|
||||
bbus_mux <= 3'b110;
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
code_cs_l <= 1'b0; // allow -cs and -rd to code ram
|
||||
code_rd_l_gate <= 1'b0;
|
||||
w_oplo_gate <= 1'b0; // assert oplo gate
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// CMPACC op - immediate
|
||||
else if ((reg_opl[7:3]==5'b01000)&&(reg_opl[2:0]==3'b111)) begin
|
||||
alu_func <= 4'b001; // alu to subtract
|
||||
w_flag_gate <= 1'b0; // update flag on s0
|
||||
bbus_mux <= 3'b110; // bbus select d_bus
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
code_cs_l <= 1'b0; // allow -cs and -rd to code ram
|
||||
code_rd_l_gate <= 1'b0;
|
||||
w_oplo_gate <= 1'b0; // assert oplo gate
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// POP, part II, load data from [SP]
|
||||
else if (reg_opl[7:3]==5'b01111) begin
|
||||
code_cs_l <= 1'b1; // don't read from code ram
|
||||
alu_func <= 4'b1000; // c_bus = b_bus
|
||||
bbus_mux <= 3'b110; // b_bus = d_bus
|
||||
w_sp_gate <= 1'b1; // disallow sp to change
|
||||
addx_mux <= 2'b10; // select sp as addx source
|
||||
sram_cs_l <= 1'b0; // select sram
|
||||
code_rd_l_gate <= 1'b0; // and read
|
||||
w_oplo_gate <= 1'b0; // and latch it into reg_oplo
|
||||
case (reg_opl[2:0])
|
||||
3'b000: w_acc_gate <= 1'b0;
|
||||
3'b001: w_ax_gate <= 1'b0;
|
||||
3'b010: w_bx_gate <= 1'b0;
|
||||
3'b100: begin
|
||||
w_flag_gate <= 1'b0;
|
||||
flag_mux <= 1'b0;
|
||||
end
|
||||
default: w_p_gate <= 1'b0;
|
||||
endcase
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// RET, part II, load hi byte of saved PC
|
||||
else if (reg_opl[7:0]==8'b11011110) begin
|
||||
code_cs_l <= 1'b1; // don't read from code ram
|
||||
alu_func <= 4'b1000; // c_bus = b_bus
|
||||
bbus_mux <= 3'b110; // b_bus = d_bus
|
||||
sp_mux <= 1'b0; // increment SP
|
||||
w_sp_gate <= 1'b0; // allow sp to change
|
||||
addx_mux <= 2'b10; // select sp as addx source
|
||||
sram_cs_l <= 1'b0; // select sram
|
||||
code_rd_l_gate <= 1'b0; // and read
|
||||
w_ophi_gate <= 1'b0; // and latch it into reg_ophi
|
||||
code_rd_l_gate <= 1'b0;
|
||||
w_oplo_gate <= 1'b0; // assert oplo gate
|
||||
next_state <= state_s3;
|
||||
end
|
||||
// these are the 3 byte branching instructions. so go and fetch the high
|
||||
// byte operand
|
||||
else begin
|
||||
code_cs_l <= 1'b0; // allow -cs and -rd to code ram
|
||||
code_rd_l_gate <= 1'b0;
|
||||
alu_func <= 4'b1000;
|
||||
w_acc_gate <= 1'b1;
|
||||
w_ax_gate <= 1'b1;
|
||||
w_bx_gate <= 1'b1;
|
||||
w_p_gate <= 1'b1;
|
||||
bbus_mux <= 3'b110;
|
||||
pc_mux <= 1'b1;
|
||||
w_pc_gate <= 1'b0; // increment pc on s3
|
||||
w_oplo_gate <= 1'b0; // assert oplo gate
|
||||
next_state <= state_s3;
|
||||
end
|
||||
end
|
||||
|
||||
/*
|
||||
** BRANCHING INSTRUCTIONS, 3 bytes, 4 cycles
|
||||
*/
|
||||
state_s3: begin
|
||||
// w_ophi_gate <= 1'b0; // latch-in high byte operand
|
||||
// w_oplo_gate <= 1'b1; // deassert oplo gate
|
||||
// Branching operations - immediate
|
||||
if((reg_opl[7]==1'b1)&&(reg_opl[2:0]==3'b000)) begin
|
||||
alu_func <= 4'b1000; // for debug, c_bus=b_bus
|
||||
bbus_mux <= 3'b110; // for debug c_bus=d_bus
|
||||
case(reg_opl[6:3])
|
||||
4'b0011: if(reg_flag[0]==1'b1) // JE
|
||||
pc_mux<=0;
|
||||
else pc_mux<=1;
|
||||
4'b0100: if(reg_flag[0]==1'b0) // JNE
|
||||
pc_mux<=0;
|
||||
else pc_mux<=1;
|
||||
4'b0101: if(reg_flag[1]==1'b1) // JP
|
||||
pc_mux<=0;
|
||||
else pc_mux<=1;
|
||||
4'b0110: if(reg_flag[1]==1'b0) // JN
|
||||
pc_mux<=0;
|
||||
else pc_mux<=1;
|
||||
4'b0111: if(reg_flag[2]==1'b1) // JC
|
||||
pc_mux<=0;
|
||||
else pc_mux<=1;
|
||||
4'b1000: if(reg_flag[2]==1'b0) // JNC
|
||||
pc_mux<=0;
|
||||
else pc_mux<=1;
|
||||
4'b1001: pc_mux<=0; // JMP unconditional
|
||||
default: pc_mux<=pc_mux;
|
||||
endcase
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
w_ophi_gate <= 1'b0; // latch-in high byte operand
|
||||
w_oplo_gate <= 1'b1; // deassert oplo gate
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// RET, part III, load lo byte of saved PC
|
||||
else if (reg_opl[7:0]==8'b11011110) begin
|
||||
code_cs_l <= 1'b1; // don't read from code ram
|
||||
alu_func <= 4'b1000; // c_bus = b_bus
|
||||
bbus_mux <= 3'b100; // b_bus = reg_pc hi
|
||||
sp_mux <= 1'b1; // increment SP
|
||||
w_sp_gate <= 1'b1; // disallow sp to change
|
||||
addx_mux <= 2'b10; // select sp as addx source
|
||||
sram_cs_l <= 1'b0; // select sram
|
||||
code_rd_l_gate <= 1'b0; // and read
|
||||
w_ophi_gate <= 1'b1;
|
||||
w_oplo_gate <= 1'b0; // and latch it into reg_oplo
|
||||
pc_mux <= 1'b0;
|
||||
w_pc_gate <= 1'b0; // PC = d_bus
|
||||
w_flag_gate <= 1'b0; // restore flag
|
||||
next_state <= state_s0;
|
||||
end
|
||||
// CALL, part I. Allow the PC to be incremented so, that
|
||||
// the PC that is pushed onto the stack is pointing to
|
||||
// the instruction after the call
|
||||
// what CALL does:
|
||||
// [SP] <- PC low byte
|
||||
// SP=SP-1
|
||||
// [SP] <- PC high 4 bits
|
||||
// SP=SP-1
|
||||
else if (reg_opl[7:0]==8'b11010110) begin
|
||||
w_pc_gate <= 1'b0;
|
||||
w_ophi_gate <= 1'b0; // latch-in high byte operand
|
||||
w_oplo_gate <= 1'b1; // deassert oplo gate
|
||||
next_state <= state_s4;
|
||||
end
|
||||
// Must be direct addresing instruction
|
||||
else begin
|
||||
next_state <= state_s4;
|
||||
w_ophi_gate <= 1'b0; // latch-in high byte operand
|
||||
w_oplo_gate <= 1'b1; // deassert oplo gate
|
||||
w_pc_gate <= 1'b1; // deassert PC gate.
|
||||
end
|
||||
end
|
||||
|
||||
/*
|
||||
** DIRECT INSTRUCTIONS, 3 byte, 5 cycles
|
||||
*/
|
||||
state_s4: begin
|
||||
|
||||
begin
|
||||
code_cs_l <= 1'b1;
|
||||
w_ophi_gate <= 1'b1; // latch-in high byte operand
|
||||
end
|
||||
|
||||
// LMD and STM instructions
|
||||
if ((reg_opl[7:4]==5'b0110)&&(reg_opl[2:0]!=3'b111)) begin
|
||||
sram_cs_l <= 1'b0; // select the sram
|
||||
addx_mux <= 2'b00; // select the sram address
|
||||
w_pc_gate <= 1'b0; // increment pc on s0
|
||||
pc_mux <= 1'b1;
|
||||
alu_func <= 4'b1000; // else c_bus = b_bus
|
||||
bbus_mux <= 3'b110; // select d_bus by default
|
||||
// if it is STM
|
||||
if (reg_opl[3]==1'b1) begin
|
||||
// while in STM, select c_bus=a_bus only if it's STM acc,xx
|
||||
if (reg_opl[2:0]==3'b000) begin
|
||||
alu_func <= 4'b1001; // if DDD=acc c_bus=acc
|
||||
end
|
||||
bbus_mux <= reg_opl[2:0]; // select the approp reg
|
||||
code_wr_l_gate <= 1'b0;
|
||||
data_bus_wr <= 1'b0; // drive data bus with c_bus
|
||||
end
|
||||
// if it is LDM
|
||||
else begin
|
||||
code_rd_l_gate <= 1'b0;
|
||||
w_oplo_gate <= 1'b0; // latchin oplo with sram data on s4
|
||||
code_rd_l_gate <= 1'b1;
|
||||
case (reg_opl[2:0]) // latch approp dest reg on s0
|
||||
3'b001: w_ax_gate <= 1'b0;
|
||||
3'b010: w_bx_gate <= 1'b0;
|
||||
3'b101: w_p_gate <= 1'b0;
|
||||
3'b100: begin
|
||||
w_flag_gate <= 1'b0;
|
||||
flag_mux <= 1'b0;
|
||||
end
|
||||
default: w_acc_gate <= 1'b0; // else, must be acc
|
||||
endcase
|
||||
end
|
||||
next_state <= state_s0;
|
||||
end // LMD if
|
||||
// CALL, 3 bytes, 6 cycles
|
||||
else if (reg_opl[7:0]==8'b11010110) begin
|
||||
code_rd_l_gate <= 1'b1;
|
||||
alu_func <= 4'b1000; // select c_bus=b_bus
|
||||
bbus_mux <= 3'b011; // select reg_pc low
|
||||
sp_mux <= 1'b1; // sp = sp - 1 on s5
|
||||
w_sp_gate <= 1'b0; // allow sp to decrement
|
||||
addx_mux <= 2'b10; // select sp as addx source
|
||||
sram_cs_l <= 1'b0; // select sram
|
||||
code_wr_l_gate <= 1'b0; // and write
|
||||
data_bus_wr <= 1'b0; // drive data bus with c_bus
|
||||
w_pc_gate <= 1'b1; //
|
||||
next_state <= state_s5;
|
||||
end // call
|
||||
end // state_s4
|
||||
|
||||
/*
|
||||
** CALL, 3 byte, 6 cycles
|
||||
** save to [SP], [SP-1] PC+1 not PC
|
||||
*/
|
||||
state_s5: begin
|
||||
if (reg_opl[7:0]==8'b11010110) begin
|
||||
alu_func <= 4'b1000; // select c_bus=b_bus
|
||||
bbus_mux <= 3'b100; // select reg_pc hi
|
||||
sp_mux <= 1'b1; // sp = sp - 1 on s0
|
||||
w_sp_gate <= 1'b0; // allow sp to decrement
|
||||
addx_mux <= 2'b10; // select sp as addx source
|
||||
sram_cs_l <= 1'b0; // select sram
|
||||
code_wr_l_gate <= 1'b0; // and write
|
||||
data_bus_wr <= 1'b0; // drive data bus with c_bus
|
||||
pc_mux <= 1'b0; // PC = d_bus
|
||||
w_pc_gate <= 1'b0; // allow pc to be changed
|
||||
next_state <= state_s0;
|
||||
end
|
||||
end // state_s5
|
||||
|
||||
endcase //state machine
|
||||
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1 @@
|
||||
work
|
||||
@@ -0,0 +1,3 @@
|
||||
verilog work "popcorn.v"
|
||||
verilog work "sequencer.v"
|
||||
verilog work "pc.v"
|
||||
Binary file not shown.
Reference in New Issue
Block a user