1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-11-28 23:49:20 +00:00
8bitworkshop/presets/verilog/cpu16.v

280 lines
7.3 KiB
Verilog

`ifndef CPU16_H
`define CPU16_H
// include ALU module
`include "cpu8.v"
/*
00000aaa 0++++bbb operation A+B->A
00001aaa 0++++bbb operation A+[B]->A
00011aaa 0++++000 operation A+imm16 -> A
00101aaa ######## load zero page
00110aaa ######## store zero page
01001aaa #####bbb load [B+#] -> A
01010aaa #####bbb store A -> [B+#]
01101aaa 0++++000 operation A+[imm16] -> A
01110aaa 00cccbbb store A -> [B+#], C -> IP
1000tttt ######## conditional branch
11+++aaa ######## immediate binary operation
*/
module CPU16(clk, reset, hold, busy,
address, data_in, data_out, write);
input clk;
input reset;
input hold;
output busy;
output [15:0] address;
input [15:0] data_in;
output [15:0] data_out;
output write;
reg [15:0] regs[0:7]; // 8 16-bit registers
reg [2:0] state; // CPU state
reg carry; // carry flag
reg zero; // zero flag
reg neg; // negative flag
wire [16:0] Y; // ALU 16-bit + carry output
reg [3:0] aluop; // ALU operation
reg [15:0] opcode; // used to decode ALU inputs
wire [2:0] rdest = opcode[10:8]; // ALU A input reg.
wire [2:0] rsrc = opcode[2:0]; // ALU B input reg.
wire Bconst = opcode[15]; // ALU B = 8-bit constant
wire Bload = opcode[11]; // ALU B = data bus
// CPU states
localparam S_RESET = 0;
localparam S_SELECT = 1;
localparam S_DECODE = 2;
localparam S_COMPUTE = 3;
localparam SP = 6; // stack ptr = register 6
localparam IP = 7; // IP = register 7
ALU #(16) alu(
.A(regs[rdest]),
.B(Bconst ? {8'b0, opcode[7:0]}
: Bload ? data_in
: regs[rsrc]),
.Y(Y),
.aluop(aluop),
.carry(carry));
always @(posedge clk)
if (reset) begin
state <= S_RESET;
busy <= 1;
end else begin
case (state)
// state 0: reset
S_RESET: begin
regs[IP] <= 16'h8000;
write <= 0;
state <= S_SELECT;
end
// state 1: select opcode address
S_SELECT: begin
write <= 0;
if (hold) begin
busy <= 1;
state <= S_SELECT;
end else begin
busy <= 0;
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
state <= S_DECODE;
end
end
// state 2: read/decode opcode
S_DECODE: begin
casez (data_in)
// 00000aaa0++++bbb operation A+B->A
16'b00000???0???????: begin
aluop <= data_in[6:3];
state <= S_COMPUTE;
end
// 00001aaa01+++bbb operation A+[B]->A
16'b00001???01??????: begin
address <= regs[data_in[2:0]];
aluop <= data_in[6:3];
state <= S_COMPUTE;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] + 1;
end
// 00011aaa0++++000 operation A+imm16 -> A
16'b00011???0????000: begin
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
aluop <= data_in[6:3];
state <= S_COMPUTE;
end
// 11+++aaa######## immediate binary operation
16'b11??????????????: begin
aluop <= data_in[14:11];
state <= S_COMPUTE;
end
// 00101aaa######## load ZP memory
16'b00101???????????: begin
address <= {8'b0, data_in[7:0]};
aluop <= `OP_LOAD_B;
state <= S_COMPUTE;
end
// 00110aaa######## store ZP memory
16'b00110???????????: begin
address <= {8'b0, data_in[7:0]};
data_out <= regs[data_in[10:8]];
write <= 1;
state <= S_SELECT;
end
// 01001aaa#####bbb [B+#] -> A
16'b01001???????????: begin
address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3]));
aluop <= `OP_LOAD_B;
state <= S_COMPUTE;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] + 1;
end
// 01010aaa#####bbb store A -> [B+#]
16'b01010???????????: begin
address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3]));
data_out <= regs[data_in[10:8]];
write <= 1;
state <= S_SELECT;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] - 1;
end
// 01011aaa0++++000 operation A+[imm16] -> A
16'b01011????????000: begin
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
aluop <= data_in[6:3];
state <= S_COMPUTE;
end
// 01110aaa00cccbbb store A -> [B+#], C -> IP
16'b01110???00??????: begin
address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3]));
data_out <= regs[data_in[10:8]];
write <= 1;
state <= S_SELECT;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] - 1;
regs[IP] <= regs[data_in[5:3]];
end
// 1000????######## conditional branch
16'b1000????????????: begin
if (
(data_in[8] && (data_in[11] == carry)) ||
(data_in[9] && (data_in[11] == zero)) ||
(data_in[10] && (data_in[11] == neg)))
begin
// relative branch, sign extended
regs[IP] <= regs[IP] + 16'($signed(data_in[7:0]));
end
state <= S_SELECT;
end
// fall-through RESET
default: begin
state <= S_RESET; // reset
end
endcase
opcode <= data_in; // (only use opcode next cycle)
end
// state 3: compute ALU op and flags
S_COMPUTE: begin
// transfer ALU output to destination
regs[rdest] <= Y[15:0];
// set carry for certain operations (4-7,12-15)
if (aluop[2]) carry <= Y[16];
// set zero flag
zero <= ~|Y[15:0];
neg <= Y[15];
// repeat CPU loop
state <= S_SELECT;
end
endcase
end
endmodule
`ifdef TOPMOD__test_CPU16_top
module test_CPU16_top(
input clk,
input reset,
output [15:0] address_bus,
output reg [15:0] to_cpu,
output [15:0] from_cpu,
output write_enable,
output [15:0] IP,
output zero,
output carry,
output busy
);
reg [15:0] ram[0:65535];
reg [15:0] rom[0:255];
assign IP = cpu.regs[7];
assign zero = cpu.zero;
assign carry = cpu.carry;
CPU16 cpu(
.clk(clk),
.reset(reset),
.hold(0),
.busy(busy),
.address(address_bus),
.data_in(to_cpu),
.data_out(from_cpu),
.write(write_enable));
always @(posedge clk)
if (write_enable) begin
ram[address_bus] <= from_cpu;
end
always @(*)
if (address_bus[15] == 0)
to_cpu = ram[address_bus];
else
to_cpu = rom[address_bus[7:0]];
`ifdef EXT_INLINE_ASM
initial begin
rom = '{
__asm
.arch femto16
.org 0x8000
.len 256
mov dx,@Fib
jsr dx
reset
Fib:
mov ax,#1
mov bx,#0
mov sp,@$6fff
Loop:
mov cx,ax
add ax,bx
mov bx,cx
push ax
pop ax
mov [42],ax
mov ax,[42]
bcc Loop
rts
__endasm
};
end
`endif
endmodule
`endif
`endif