1
0
Fork 0

Add SAP-3

This commit is contained in:
Austin Morlan 2023-03-03 10:43:11 -08:00
parent eb7cc9dc79
commit 3c0263fc05
Signed by: austin
GPG Key ID: FD6B27654AF5E348
11 changed files with 1615 additions and 6 deletions

View File

@ -1,9 +1,13 @@
# FPGA Computer
8-bit computer modeled after the SAP-1 from the book [Digital Computer
8-bit computer modeled after the Simple-As-Possible computers from the book [Digital Computer
Electronics](https://www.goodreads.com/book/show/942643.Digital_Computer_Electronics) by Malvino and
Brown.
The SAP-3 is the final iteration of the computer and shares an instruction set with the Intel
8080/8085, minus a few instructions.
* [Blog post about the SAP-1.](https://austinmorlan.com/posts/fpga_computer_sap1/)
* [Blog post about the SAP-2.](https://austinmorlan.com/posts/fpga_computer_sap2/)
* [Blog post about the SAP-3.](https://austinmorlan.com/posts/fpga_computer_sap3/)

View File

@ -35,6 +35,17 @@ SAP2_MODULES="
SAP2_TOP=$SRC_DIR/sap2/top.v
SAP2_TB=$SRC_DIR/sap2/top_tb.v
SAP3_MODULES="
$SRC_DIR/sap3/alu.v
$SRC_DIR/sap3/clock.v
$SRC_DIR/sap3/controller.v
$SRC_DIR/sap3/ir.v
$SRC_DIR/sap3/memory.v
$SRC_DIR/sap3/reg_file.v"
SAP3_TOP=$SRC_DIR/sap3/top.v
SAP3_TB=$SRC_DIR/sap3/top_tb.v
if [ -z "$COMMAND" ]; then
mkdir -p $BUILD_DIR/sap1
@ -54,6 +65,15 @@ if [ -z "$COMMAND" ]; then
$BIN_DIR/icepack hardware.asc hardware.bin
popd > /dev/null
mkdir -p $BUILD_DIR/sap3
pushd $BUILD_DIR/sap3 > /dev/null
$BIN_DIR/yosys -p "synth_ice40 -json hardware.json" $SAP3_MODULES $SAP3_TOP
$BIN_DIR/nextpnr-ice40 --lp8k --package cm81 --json hardware.json --asc hardware.asc --pcf $SRC_DIR/pins.pcf -q
$BIN_DIR/icepack hardware.asc hardware.bin
popd > /dev/null
elif [ "$COMMAND" == "init" ]; then
virtualenv .env
source .env/bin/activate
@ -70,13 +90,14 @@ elif [ "$COMMAND" == "program" ]; then
exit 1
elif [ "$VERSION" == "sap1" ]; then
pushd $BUILD_DIR/sap1 > /dev/null
sudo tinyprog -p hardware.bin
popd > /dev/null
elif [ "$VERSION" == "sap2" ]; then
pushd $BUILD_DIR/sap2 > /dev/null
sudo tinyprog -p hardware.bin
popd > /dev/null
elif [ "$VERSION" == "sap3" ]; then
pushd $BUILD_DIR/sap3 > /dev/null
fi
sudo tinyprog -p hardware.bin
popd > /dev/null
elif [ "$COMMAND" == "sim" ]; then
if [ -z "$VERSION" ]; then
echo "sim needs a version"
@ -101,8 +122,17 @@ elif [ "$COMMAND" == "sim" ]; then
popd > /dev/null
gtkwave $BUILD_DIR/sap2/top_tb.vcd $BUILD_DIR/sap2/top_tb.gtkw
fi
elif [ "$VERSION" == "sap3" ]; then
mkdir -p $BUILD_DIR/sap3
pushd $SRC_DIR/sap3 > /dev/null
$BIN_DIR/iverilog -o $BUILD_DIR/sap3/top_tb $SAP3_MODULES $SAP3_TB
$BIN_DIR/vvp $BUILD_DIR/sap3/top_tb
mv top_tb.vcd $BUILD_DIR/sap3
popd > /dev/null
gtkwave $BUILD_DIR/sap3/top_tb.vcd $BUILD_DIR/sap3/top_tb.gtkw
fi
else
echo "Invalid arguments"
fi

173
src/sap3/alu.v Normal file
View File

@ -0,0 +1,173 @@
module alu(
input clk,
input rst,
input cs,
input flags_we,
input a_we,
input a_store,
input a_restore,
input tmp_we,
input[4:0] op,
input[7:0] bus,
output[7:0] flags,
output[7:0] out
);
reg carry;
wire flg_c;
wire flg_z;
wire flg_p;
wire flg_s;
reg[7:0] acc;
reg[7:0] flg;
reg[7:0] act; // Internal
reg[7:0] tmp; // Internal
localparam FLG_Z = 0;
localparam FLG_C = 1;
localparam FLG_P = 2;
localparam FLG_S = 3;
localparam OP_ADD = 5'b00000;
localparam OP_ADC = 5'b00001;
localparam OP_SUB = 5'b00010;
localparam OP_SBB = 5'b00011;
localparam OP_ANA = 5'b00100;
localparam OP_XRA = 5'b00101;
localparam OP_ORA = 5'b00110;
localparam OP_CMP = 5'b00111;
localparam OP_RLC = 5'b01000;
localparam OP_RRC = 5'b01001;
localparam OP_RAL = 5'b01010;
localparam OP_RAR = 5'b01011;
localparam OP_DAA = 5'b01100; // Unsupported
localparam OP_CMA = 5'b01101;
localparam OP_STC = 5'b01110;
localparam OP_CMC = 5'b01111;
localparam OP_INR = 5'b10000;
localparam OP_DCR = 5'b10001;
assign flg_c = (carry == 1'b1);
assign flg_z = (acc[7:0] == 8'b0);
assign flg_s = acc[7];
assign flg_p = ~^acc[7:0];
always @(posedge clk, posedge rst) begin
if (rst) begin
acc <= 8'b0;
act <= 8'b0;
tmp <= 8'b0;
carry <= 1'b0;
end else begin
if (a_we) begin
acc <= bus;
end else if (a_restore) begin
acc <= act;
end else if (cs) begin
case (op)
OP_ADD: begin
{carry, acc} <= acc + tmp;
end
OP_ADC: begin
{carry, acc} <= acc + tmp + flg[FLG_C];
end
OP_SUB: begin
{carry, acc} <= acc - tmp;
end
OP_SBB: begin
{carry, acc} <= acc - tmp - flg[FLG_C];
end
OP_ANA: begin
{carry, acc} <= acc & tmp;
end
OP_XRA: begin
{carry, acc} <= acc ^ tmp;
end
OP_ORA: begin
{carry, acc} <= acc | tmp;
end
OP_CMP: begin
act <= acc - tmp;
end
OP_RLC: begin
carry <= acc[7];
acc <= acc << 1;
end
OP_RRC: begin
carry <= acc[0];
acc <= acc >> 1;
end
OP_RAL: begin
carry <= acc[7];
acc <= (acc << 1 | {7'b0, flg[FLG_C]});
end
OP_RAR: begin
carry <= acc[0];
acc <= (acc >> 1 | {flg[FLG_C], 7'b0});
end
OP_CMA: begin
acc <= ~acc;
end
OP_STC: begin
carry <= 1'b1;
end
OP_CMC: begin
carry <= ~flg[FLG_C];
end
OP_INR: begin
acc <= acc + 1;
end
OP_DCR: begin
acc <= acc - 1;
end
endcase
end
if (a_store)
act <= acc;
if (tmp_we)
tmp <= bus;
end
end
always @(negedge clk, posedge rst) begin
if (rst) begin
flg <= 8'b0;
end else if (flags_we) begin
flg <= bus;
end else begin
if (cs) begin
case (op)
OP_ADD, OP_ADC, OP_SUB, OP_SBB, OP_ANA, OP_XRA, OP_ORA: begin
flg[FLG_C] <= flg_c;
flg[FLG_Z] <= flg_z;
flg[FLG_S] <= flg_s;
flg[FLG_P] <= flg_p;
end
OP_CMP: begin
flg[FLG_Z] <= (act == 8'b0);
end
OP_INR, OP_DCR: begin
flg[FLG_Z] <= flg_z;
flg[FLG_S] <= flg_s;
flg[FLG_P] <= flg_p;
end
OP_RLC, OP_RRC, OP_RAL, OP_RAR, OP_STC, OP_CMC: begin
flg[FLG_C] <= flg_c;
end
endcase
end
end
end
assign flags = flg;
assign out = acc;
endmodule

9
src/sap3/clock.v Normal file
View File

@ -0,0 +1,9 @@
module clock(
input hlt,
input clk_in,
output clk_out);
assign clk_out = (hlt) ? 1'b0 : clk_in;
endmodule

928
src/sap3/controller.v Normal file
View File

@ -0,0 +1,928 @@
module controller(
input clk,
input rst,
input[7:0] opcode,
input[7:0] flags,
output[32:0] out
);
localparam DISPLAY = 32;
localparam HLT = 31;
localparam ALU_CS = 30;
localparam ALU_FLAGS_WE = 29;
localparam ALU_A_WE = 28;
localparam ALU_A_STORE = 27;
localparam ALU_A_RESTORE = 26;
localparam ALU_TMP_WE = 25;
localparam ALU_OP4 = 24;
localparam ALU_OP0 = 20;
localparam ALU_OE = 19;
localparam ALU_FLAGS_OE = 18;
localparam REG_RD_SEL4 = 17;
localparam REG_RD_SEL0 = 13;
localparam REG_WR_SEL4 = 12;
localparam REG_WR_SEL0 = 8;
localparam REG_EXT1 = 7;
localparam REG_EXT0 = 6;
localparam REG_OE = 5;
localparam REG_WE = 4;
localparam MEM_WE = 3;
localparam MEM_MAR_WE = 2;
localparam MEM_OE = 1;
localparam IR_WE = 0;
localparam REG_INC = 2'b01;
localparam REG_DEC = 2'b10;
localparam REG_INC2 = 2'b11;
localparam REG_BC = 5'b10000;
localparam REG_BC_B = 5'b00000;
localparam REG_BC_C = 5'b00001;
localparam REG_DE = 5'b10010;
localparam REG_DE_D = 5'b00010;
localparam REG_DE_E = 5'b00011;
localparam REG_HL = 5'b10100;
localparam REG_HL_H = 5'b00100;
localparam REG_HL_L = 5'b00101;
localparam REG_WZ = 5'b10110;
localparam REG_WZ_W = 5'b00110;
localparam REG_WZ_Z = 5'b00111;
localparam REG_PC = 5'b11000;
localparam REG_PC_P = 5'b01000;
localparam REG_PC_C = 5'b01001;
localparam REG_SP = 5'b11010;
localparam REG_SP_S = 5'b01010;
localparam REG_SP_P = 5'b01011;
reg[32:0] ctrl_word;
reg[3:0] stage;
reg stage_rst;
assign out = ctrl_word;
always @(negedge clk, posedge rst) begin
if (rst) begin
stage <= 0;
end else begin
if (stage_rst) begin
stage <= 0;
end else begin
stage <= stage + 1;
end
end
end
always @(*) begin
ctrl_word = 0;
stage_rst = 0;
if (stage == 0) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 1) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[IR_WE] = 1'b1;
end else if (stage == 2) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else begin
casez (opcode)
// NOP
8'o000: begin
stage_rst = 1'b1;
end
// HLT
8'o166: begin
if (stage == 3) begin
ctrl_word[HLT] = 1'b1;
end
end
// MOV Rd, M
// opcode[5:3] - Rd
8'o1?6: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
if (opcode[5:3] == 3'b111) begin
ctrl_word[ALU_A_WE] = 1'b1;
end else begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]};
ctrl_word[REG_WE] = 1'b1;
end
ctrl_word[MEM_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// MOV M, Rs
// opcode[2:0] - Rs
8'o16?: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
if (opcode[2:0] == 3'b111) begin
ctrl_word[ALU_OE] = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[2:0]};
ctrl_word[REG_OE] = 1'b1;
end
ctrl_word[MEM_WE] = 1'b1;
stage_rst = 1'b1;
end
end
// MOV Rd, Rs
// opcode[5:3] - Rd
// opcode[2:0] - Rs
8'o1??: begin
if (stage == 3) begin
if (opcode[2:0] == 3'b111) begin
ctrl_word[ALU_OE] = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[2:0]};
ctrl_word[REG_OE] = 1'b1;
end
if (opcode[5:3] == 3'b111) begin
ctrl_word[ALU_A_WE] = 1'b1;
end else begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]};
ctrl_word[REG_WE] = 1'b1;
end
stage_rst = 1'b1;
end
end
// INX, DCX
// opcode[5:4] - 16-bit Register
// opcode[3] - Dec(1) / Inc (0)
8'o0?3: begin
if (stage == 3) begin
if (opcode[5:4] == 2'b11)
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
else
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b10, opcode[5:4], 1'b0};
ctrl_word[REG_EXT1:REG_EXT0] = {opcode[3], ~opcode[3]};
stage_rst = 1'b1;
end
end
// INR/DCR M
// opcode[5:3] - Rs
// opcode[0] - INR (0), DCR (1)
8'o064: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[ALU_A_STORE] = 1'b1;
ctrl_word[ALU_A_WE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = {4'b1000, opcode[0]};
end else if (stage == 6) begin
ctrl_word[ALU_OE] = 1'b1;
ctrl_word[ALU_A_RESTORE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
stage_rst = 1'b1;
end
end
// INR/DCR Rs
// opcode[5:3] - Rs
// opcode[0] - INR (0), DCR (1)
8'o0?4, 8'o0?5: begin
if (stage == 3) begin
if (opcode[5:3] == 3'b111) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = 5'b10000;
stage_rst = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:3]};
ctrl_word[REG_OE] = 1'b1;
ctrl_word[ALU_A_STORE] = 1'b1;
ctrl_word[ALU_A_WE] = 1'b1;
end
end else if (stage == 4) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = {4'b1000, opcode[0]};
end else if (stage == 5) begin
ctrl_word[ALU_OE] = 1'b1;
ctrl_word[ALU_A_RESTORE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]};
ctrl_word[REG_WE] = 1'b1;
stage_rst = 1'b1;
end
end
// Arithmetic/Logic Set 0 (M)
// opcode[5:3] - ALU Op
8'o2?6: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[ALU_TMP_WE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]};
stage_rst = 1'b1;
end
end
// Arithmetic/Logic Set 0
// opcode[2:0] - Rs
// opcode[5:3] - ALU Op
8'o2??: begin
if (stage == 3) begin
if (opcode[2:0] == 3'b111) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]};
stage_rst = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[2:0]};
ctrl_word[REG_OE] = 1'b1;
end
ctrl_word[ALU_TMP_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]};
stage_rst = 1'b1;
end
end
// Arithmetic/Logic Set 1
// opcode[5:3] - ALU Op
8'o0?7: begin
if (stage == 3) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = {2'b01, opcode[5:3]};
stage_rst = 1'b1;
end
end
// Arithmetic/Logic Immediate
// opcode[5:3] - ALU Op
8'o3?6: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[ALU_TMP_WE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = {2'b0, opcode[5:3]};
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
stage_rst = 1'b1;
end
end
// MVI M, d8
8'o066: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, REG_WZ_W};
ctrl_word[REG_WE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, REG_WZ_W};
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
stage_rst = 1'b1;
end
end
// MVI Rd, d8
// opcode[5:3] - Rd
8'o0?6: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
if (opcode[5:3] == 3'b111) begin
ctrl_word[ALU_A_WE] = 1'b1;
end else begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:3]};
ctrl_word[REG_WE] = 1'b1;
end
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
stage_rst = 1'b1;
end
end
// LXI
// opcode[5:4] - Extended Register
8'o001, 8'o021, 8'o041, 8'o061: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
end else if (stage == 8) begin
if (opcode[5:4] == 2'b11)
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
else
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b10, opcode[5:4], 1'b0};
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[REG_WE] = 1'b1;
end else if (stage == 9) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
stage_rst = 1'b1;
end
end
// LDA/STA a16
// opcode[3]: STA (0) / LDA (1)
8'o062, 8'o072: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 9) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 10) begin
if (opcode[3] == 0) begin
ctrl_word[ALU_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else begin
ctrl_word[ALU_A_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end
stage_rst = 1'b1;
end
end
// STAX/LDAX Rs
// opcode[5:4] - Rs
// opcode[3] - STAX (0) / LDAX (1)
8'o002, 8'o012, 8'o022, 8'o032: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b0};
ctrl_word[REG_OE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b1};
ctrl_word[REG_OE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
if (opcode[3] == 1'b0) begin
ctrl_word[ALU_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else begin
ctrl_word[ALU_A_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end
stage_rst = 1'b1;
end
end
// SHLD, LHLD
// opcode[3] - SHLD (0) / LHLD (1)
8'o042, 8'o052: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[MEM_OE] = 1'b1;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 9) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 10) begin
if (opcode[3] == 1'b0) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_H;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_HL_H;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end
end else if (stage == 11) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 12) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 13) begin
if (opcode[3] == 1'b0) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_L;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_HL_L;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end
stage_rst = 1'b1;
end
end
// DAD
// opcode[5:4] - Extended Register
8'o011, 8'o031, 8'o051, 8'o071: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_L;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[ALU_A_STORE] = 1'b1;
ctrl_word[ALU_A_WE] = 1'b1;
end else if (stage == 4) begin
if (opcode[5:4] == 2'b11) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP_P;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b1};
end
ctrl_word[REG_OE] = 1'b1;
ctrl_word[ALU_TMP_WE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = 5'b00000; // Add
end else if (stage == 6) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[ALU_OE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_HL_H;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[ALU_A_WE] = 1'b1;
end else if (stage == 8) begin
if (opcode[5:4] == 2'b11) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP_S;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b0};
end
ctrl_word[REG_OE] = 1'b1;
ctrl_word[ALU_TMP_WE] = 1'b1;
end else if (stage == 9) begin
ctrl_word[ALU_CS] = 1'b1;
ctrl_word[ALU_OP4:ALU_OP0] = 5'b00001; // Add w/ Carry
end else if (stage == 10) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[ALU_OE] = 1'b1;
ctrl_word[ALU_A_RESTORE] = 1'b1;
end else if (stage == 11) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_HL;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// JMP
8'o303: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// Jump Conditional
// opcode[5:4] - flag
// opcode[3] - set (1) / unset (0)
8'o3?2: begin
if (stage == 3) begin
if (flags[opcode[5:4]] != opcode[3]) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC2;
stage_rst = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end
end else if (stage == 4) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// Call Conditional
// opcode[5:4] - flag
// opcode[3] - set (1) / unset (0)
8'o3?4: begin
if (stage == 3) begin
if (flags[opcode[5:4]] != opcode[3]) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC2;
stage_rst = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end
end else if (stage == 4) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 9) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC;
end else if (stage == 10) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 11) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_C;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else if (stage == 12) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC;
end else if (stage == 13) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 14) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_P;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else if (stage == 15) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// CALL
8'o315: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 9) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC;
end else if (stage == 10) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 11) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_C;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else if (stage == 12) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC;
end else if (stage == 13) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 14) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_PC_P;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_WE] = 1'b1;
end else if (stage == 15) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// Return Conditional
// opcode[5:4] - flag
// opcode[3] - set (1) / unset (0)
8'o3?0: begin
if (stage == 3) begin
if (flags[opcode[5:4]] != opcode[3]) begin
stage_rst = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end
end else if (stage == 4) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 9) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// RET
8'o311: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_W;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_WZ_Z;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 9) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_WZ;
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_WE] = 1'b1;
ctrl_word[REG_OE] = 1'b1;
stage_rst = 1'b1;
end
end
// PUSH Rs
// opcode[5:4] - Extended Register
8'o3?5: begin
if (stage == 3) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC;
end else if (stage == 4) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 5) begin
if (opcode[5:4] == 2'b11) begin // PSW
ctrl_word[ALU_OE] = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b0};
ctrl_word[REG_OE] = 1'b1;
end
ctrl_word[MEM_WE] = 1'b1;
end else if (stage == 6) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_DEC;
end else if (stage == 7) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 8) begin
if (opcode[5:4] == 2'b11) begin // PSW
ctrl_word[ALU_FLAGS_OE] = 1'b1;
end else begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = {2'b0, opcode[5:4], 1'b1};
ctrl_word[REG_OE] = 1'b1;
end
ctrl_word[MEM_WE] = 1'b1;
stage_rst = 1'b1;
end
end
// POP Rs
// opcode[5:4] - Extended Register
8'o301, 8'o321, 8'o341, 8'o361: begin
if (stage == 3) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 4) begin
if (opcode[5:4] == 2'b11) begin // PSW
ctrl_word[ALU_FLAGS_WE] = 1'b1;
end else begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:4], 1'b1};
ctrl_word[REG_WE] = 1'b1;
end
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 5) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
end else if (stage == 6) begin
ctrl_word[REG_RD_SEL4:REG_RD_SEL0] = REG_SP;
ctrl_word[REG_OE] = 1'b1;
ctrl_word[MEM_MAR_WE] = 1'b1;
end else if (stage == 7) begin
if (opcode[5:4] == 2'b11) begin // PSW
ctrl_word[ALU_A_WE] = 1'b1;
end else begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = {2'b0, opcode[5:4], 1'b0};
ctrl_word[REG_WE] = 1'b1;
end
ctrl_word[MEM_OE] = 1'b1;
end else if (stage == 8) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_SP;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
stage_rst = 1'b1;
end
end
// OUT
8'o323: begin
if (stage == 3) begin
ctrl_word[REG_WR_SEL4:REG_WR_SEL0] = REG_PC;
ctrl_word[REG_EXT1:REG_EXT0] = REG_INC;
ctrl_word[DISPLAY] = 1'b1;
stage_rst = 1'b1;
end
end
endcase
end
end
endmodule

22
src/sap3/ir.v Normal file
View File

@ -0,0 +1,22 @@
module ir(
input clk,
input rst,
input we,
input[7:0] bus,
output[7:0] out
);
reg[7:0] ir;
always @(posedge clk, posedge rst) begin
if (rst) begin
ir <= 8'b0;
end else if (we) begin
ir <= bus;
end
end
assign out = ir;
endmodule

32
src/sap3/memory.v Normal file
View File

@ -0,0 +1,32 @@
module memory(
input clk,
input rst,
input mar_we,
input ram_we,
input[15:0] bus,
output[7:0] out
);
initial begin
$readmemh("program.bin", ram);
end
reg[15:0] mar;
reg[7:0] ram[0:255];
always @(posedge clk, posedge rst) begin
if (rst)
mar <= 16'b0;
else if (mar_we)
mar <= bus;
end
always @(posedge clk) begin
if (ram_we)
ram[mar] <= bus[7:0];
end
assign out = ram[mar];
endmodule

32
src/sap3/program.bin Normal file
View File

@ -0,0 +1,32 @@
31 f0 00 3e 01 06 00 d3
ff 4f 78 fe 01 79 ca 17
00 c2 20 00 c3 07 00 1f
fe 01 cc 29 00 c3 07 00
17 fe 80 cc 2c 00 c3 07
00 06 00 c9 06 01 c9 76
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00

72
src/sap3/reg_file.v Normal file
View File

@ -0,0 +1,72 @@
module reg_file(
input clk,
input rst,
input[4:0] rd_sel,
input[4:0] wr_sel,
input[1:0] ext,
input we,
input[15:0] data_in,
output[15:0] data_out
);
// 8-bit
// 0 1
// 0000_ [ B ][ C ]
// 0001_ [ D ][ E ]
// 0010_ [ H ][ L ]
// 0011_ [ W ][ Z ]
// 0100_ [ P ][ C ]
// 0101_ [ S ][ P ]
// 16-bit (ext)
//
// 10000 [ BC ]
// 10010 [ DE ]
// 10100 [ HL ]
// 10110 [ WZ ]
// 11000 [ PC ]
// 11010 [ SP ]
reg[7:0] data[0:11];
reg[15:0] data_out;
wire wr_ext = wr_sel[4];
wire rd_ext = rd_sel[4];
wire[3:0] wr_dst = wr_sel[3:0];
wire[3:0] rd_src = rd_sel[3:0];
localparam EXT_INC = 2'b01;
localparam EXT_DEC = 2'b10;
localparam EXT_INC2 = 2'b11;
always @(posedge clk, posedge rst) begin
if (rst) begin
data[0] <= 8'b0; data[1] <= 8'b0; data[2] <= 8'b0; data[3] <= 8'b0; data[4] <= 8'b0;
data[5] <= 8'b0; data[6] <= 8'b0; data[7] <= 8'b0; data[8] <= 8'b0; data[9] <= 8'b0;
data[10] <= 8'b0; data[11] <= 8'b0;
end else begin
if (ext == EXT_INC) begin
{data[wr_dst], data[wr_dst+1]} <= {data[wr_dst], data[wr_dst+1]} + 1;
end else if (ext == EXT_INC2) begin
{data[wr_dst], data[wr_dst+1]} <= {data[wr_dst], data[wr_dst+1]} + 2;
end else if (ext == EXT_DEC) begin
{data[wr_dst], data[wr_dst+1]} <= {data[wr_dst], data[wr_dst+1]} - 1;
end else if (we) begin
if (wr_ext) begin
{data[wr_dst], data[wr_dst+1]} <= data_in;
end else begin
data[wr_dst] <= data_in[7:0];
end
end
end
end
always @(*) begin
if (rd_ext) begin
data_out = {data[rd_src], data[rd_src+1]};
end else begin
data_out = {8'b0, data[rd_src]};
end
end
endmodule

153
src/sap3/top.v Normal file
View File

@ -0,0 +1,153 @@
module top(
input CLK,
input PIN_24,
output PIN_4,
output PIN_5,
output PIN_6,
output PIN_7,
output PIN_8,
output PIN_9,
output PIN_10,
output PIN_11,
);
assign rst = PIN_24;
assign {PIN_4, PIN_5, PIN_6, PIN_7, PIN_8, PIN_9, PIN_10, PIN_11} = out;
reg[7:0] out;
always @(posedge clk, posedge rst) begin
if (rst) begin
out = 8'b0;
end else if (display) begin
out = alu_out;
end
end
reg[18:0] bus;
always @(*) begin
bus = 16'b0;
if (reg_oe)
bus = reg_out;
else if (mem_oe)
bus = {8'b0, mem_out};
else if (alu_oe)
bus = {8'b0, alu_out};
else if (alu_flags_oe)
bus = {8'b0, alu_flags};
end
reg[23:0] clk_slow;
always @(posedge CLK) begin
clk_slow <= clk_slow + 1;
end
wire rst;
wire hlt;
wire clk;
clock clock(
.hlt(hlt),
.clk_in(clk_slow[14]),
.clk_out(clk)
);
wire[4:0] reg_rd_sel;
wire[4:0] reg_wr_sel;
wire[1:0] reg_ext;
wire reg_oe;
wire reg_we;
wire[15:0] reg_out;
reg_file reg_file(
.clk(clk),
.rst(rst),
.rd_sel(reg_rd_sel),
.wr_sel(reg_wr_sel),
.ext(reg_ext),
.we(reg_we),
.data_in(bus),
.data_out(reg_out)
);
wire mem_mar_we;
wire mem_ram_we;
wire mem_oe;
wire[7:0] mem_out;
memory memory(
.clk(clk),
.rst(rst),
.mar_we(mem_mar_we),
.ram_we(mem_ram_we),
.bus(bus),
.out(mem_out)
);
wire ir_we;
wire[7:0] ir_out;
ir ir(
.clk(clk),
.rst(rst),
.we(ir_we),
.bus(bus[7:0]),
.out(ir_out)
);
wire alu_cs;
wire alu_flags_we;
wire alu_a_we;
wire alu_a_store;
wire alu_a_restore;
wire alu_tmp_we;
wire alu_oe;
wire alu_flags_oe;
wire[4:0] alu_op;
wire[7:0] alu_flags;
wire[7:0] alu_out;
alu alu(
.clk(clk),
.rst(rst),
.cs(alu_cs),
.flags_we(alu_flags_we),
.a_we(alu_a_we),
.a_store(alu_a_store),
.a_restore(alu_a_restore),
.tmp_we(alu_tmp_we),
.op(alu_op),
.bus(bus[7:0]),
.flags(alu_flags),
.out(alu_out)
);
wire display;
controller controller(
.clk(clk),
.rst(rst),
.opcode(ir_out),
.flags(alu_flags),
.out({
display,
hlt,
alu_cs,
alu_flags_we,
alu_a_we,
alu_a_store,
alu_a_restore,
alu_tmp_we,
alu_op,
alu_oe,
alu_flags_oe,
reg_rd_sel,
reg_wr_sel,
reg_ext,
reg_oe,
reg_we,
mem_ram_we,
mem_mar_we,
mem_oe,
ir_we
})
);
endmodule

154
src/sap3/top_tb.v Normal file
View File

@ -0,0 +1,154 @@
module top_tb();
initial begin
$dumpfile("top_tb.vcd");
$dumpvars(0, top_tb);
for (i = 0; i < 12; i++) begin
$dumpvars(0, reg_file.data[i]);
end
for (i = 230; i < 256; i++) begin
$dumpvars(0, memory.ram[i]);
end
rst = 1;
#1 rst = 0;
end
reg clk_in = 0;
integer i;
initial begin
for (i = 0; i < 8096; i++) begin
#1 clk_in = ~clk_in;
end
end
reg[7:0] out;
always @(posedge clk, posedge rst) begin
if (rst) begin
out = 8'b0;
end else if (display) begin
out = alu_out;
end
end
reg[15:0] bus;
always @(*) begin
bus = 16'b0;
if (reg_oe)
bus = reg_out;
else if (mem_oe)
bus = {8'b0, mem_out};
else if (alu_oe)
bus = {8'b0, alu_out};
else if (alu_flags_oe)
bus = {8'b0, alu_flags};
end
reg rst;
wire hlt;
wire clk;
clock clock(
.hlt(hlt),
.clk_in(clk_in),
.clk_out(clk)
);
wire[4:0] reg_rd_sel;
wire[4:0] reg_wr_sel;
wire[1:0] reg_ext;
wire reg_oe;
wire reg_we;
wire[15:0] reg_out;
reg_file reg_file(
.clk(clk),
.rst(rst),
.rd_sel(reg_rd_sel),
.wr_sel(reg_wr_sel),
.ext(reg_ext),
.we(reg_we),
.data_in(bus),
.data_out(reg_out)
);
wire mem_mar_we;
wire mem_ram_we;
wire mem_oe;
wire[7:0] mem_out;
memory memory(
.clk(clk),
.rst(rst),
.mar_we(mem_mar_we),
.ram_we(mem_ram_we),
.bus(bus),
.out(mem_out)
);
wire ir_we;
wire[7:0] ir_out;
ir ir(
.clk(clk),
.rst(rst),
.we(ir_we),
.bus(bus[7:0]),
.out(ir_out)
);
wire alu_cs;
wire alu_flags_we;
wire alu_a_we;
wire alu_a_store;
wire alu_a_restore;
wire alu_tmp_we;
wire alu_oe;
wire alu_flags_oe;
wire[4:0] alu_op;
wire[7:0] alu_flags;
wire[7:0] alu_out;
alu alu(
.clk(clk),
.rst(rst),
.cs(alu_cs),
.flags_we(alu_flags_we),
.a_we(alu_a_we),
.a_store(alu_a_store),
.a_restore(alu_a_restore),
.tmp_we(alu_tmp_we),
.op(alu_op),
.bus(bus[7:0]),
.flags(alu_flags),
.out(alu_out)
);
controller controller(
.clk(clk),
.rst(rst),
.opcode(ir_out),
.flags(alu_flags),
.out({
display,
hlt,
alu_cs,
alu_flags_we,
alu_a_we,
alu_a_store,
alu_a_restore,
alu_tmp_we,
alu_op,
alu_oe,
alu_flags_oe,
reg_rd_sel,
reg_wr_sel,
reg_ext,
reg_oe,
reg_we,
mem_ram_we,
mem_mar_we,
mem_oe,
ir_we
})
);
endmodule