mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-11 15:30:31 +00:00
moved around ALU ops, 16-bit cpu, reg/wire
This commit is contained in:
parent
f6d320a05b
commit
20ddb8a11f
@ -3,7 +3,7 @@
|
|||||||
module seven_segment_decoder(digit, segments);
|
module seven_segment_decoder(digit, segments);
|
||||||
|
|
||||||
input [3:0] digit;
|
input [3:0] digit;
|
||||||
output [6:0] segments;
|
output reg [6:0] segments;
|
||||||
|
|
||||||
always @(*)
|
always @(*)
|
||||||
case(digit)
|
case(digit)
|
||||||
@ -26,7 +26,7 @@ module segments_to_bitmap(segments, line, bits);
|
|||||||
|
|
||||||
input [6:0] segments;
|
input [6:0] segments;
|
||||||
input [2:0] line;
|
input [2:0] line;
|
||||||
output [4:0] bits;
|
output reg [4:0] bits;
|
||||||
|
|
||||||
always @(*)
|
always @(*)
|
||||||
case (line)
|
case (line)
|
||||||
|
@ -5,20 +5,25 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
00000aaa 0++++bbb operation A+B->A
|
00000aaa 0++++bbb operation A+B->A
|
||||||
00001ttt ######## conditional branch
|
00001aaa 0++++bbb operation A+[B]->A
|
||||||
00100aaa ######## load constant
|
00011aaa 0++++000 operation A+imm16 -> A
|
||||||
00101aaa ######## load memory
|
00101aaa ######## load zero page
|
||||||
00110aaa ######## store memory
|
00110aaa ######## store zero page
|
||||||
01000aaa #####bbb load [B+#] -> A
|
01001aaa #####bbb load [B+#] -> A
|
||||||
01010aaa #####bbb store A -> [B+#]
|
01010aaa #####bbb store A -> [B+#]
|
||||||
10+++aaa 10+++aaa dual unary operation
|
01101aaa 0++++000 operation A+[imm16] -> A
|
||||||
|
01110aaa 00cccbbb store A -> [B+#], C -> IP
|
||||||
|
1000tttt ######## conditional branch
|
||||||
11+++aaa ######## immediate binary operation
|
11+++aaa ######## immediate binary operation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module CPU16(clk, reset, address, data_in, data_out, write);
|
module CPU16(clk, reset, halt, busy,
|
||||||
|
address, data_in, data_out, write);
|
||||||
|
|
||||||
input clk;
|
input clk;
|
||||||
input reset;
|
input reset;
|
||||||
|
input halt;
|
||||||
|
output busy;
|
||||||
output [15:0] address;
|
output [15:0] address;
|
||||||
input [15:0] data_in;
|
input [15:0] data_in;
|
||||||
output [15:0] data_out;
|
output [15:0] data_out;
|
||||||
@ -37,6 +42,7 @@ module CPU16(clk, reset, address, data_in, data_out, write);
|
|||||||
reg [3:0] aluop;
|
reg [3:0] aluop;
|
||||||
wire [2:0] rdest = opcode[10:8];
|
wire [2:0] rdest = opcode[10:8];
|
||||||
wire [2:0] rsrc = opcode[2:0];
|
wire [2:0] rsrc = opcode[2:0];
|
||||||
|
wire Bconst = opcode[15]; // TODO
|
||||||
wire Bload = opcode[11]; // TODO
|
wire Bload = opcode[11]; // TODO
|
||||||
|
|
||||||
localparam S_RESET = 0;
|
localparam S_RESET = 0;
|
||||||
@ -44,19 +50,22 @@ module CPU16(clk, reset, address, data_in, data_out, write);
|
|||||||
localparam S_DECODE = 2;
|
localparam S_DECODE = 2;
|
||||||
localparam S_COMPUTE = 3;
|
localparam S_COMPUTE = 3;
|
||||||
|
|
||||||
|
localparam SP = 6; // stack ptr = register 6
|
||||||
localparam IP = 7; // IP = register 7
|
localparam IP = 7; // IP = register 7
|
||||||
|
|
||||||
ALU #(16) alu(
|
ALU #(16) alu(
|
||||||
.A(regs[rdest]),
|
.A(regs[rdest]),
|
||||||
.B(regs[rsrc]),
|
.B(Bconst ? {8'b0, opcode[7:0]}
|
||||||
|
: Bload ? data_in
|
||||||
|
: regs[rsrc]),
|
||||||
.Y(Y),
|
.Y(Y),
|
||||||
.aluop(aluop),
|
.aluop(aluop),
|
||||||
.carry(carry));
|
.carry(carry));
|
||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
if (reset) begin
|
if (reset) begin
|
||||||
state <= 0;
|
state <= S_RESET;
|
||||||
write <= 0;
|
busy <= 1;
|
||||||
end else begin
|
end else begin
|
||||||
case (state)
|
case (state)
|
||||||
// state 0: reset
|
// state 0: reset
|
||||||
@ -67,46 +76,102 @@ module CPU16(clk, reset, address, data_in, data_out, write);
|
|||||||
end
|
end
|
||||||
// state 1: select opcode address
|
// state 1: select opcode address
|
||||||
S_SELECT: begin
|
S_SELECT: begin
|
||||||
|
write <= 0;
|
||||||
|
if (halt) begin
|
||||||
|
busy <= 1;
|
||||||
|
state <= S_SELECT;
|
||||||
|
end else begin
|
||||||
|
busy <= 0;
|
||||||
address <= regs[IP];
|
address <= regs[IP];
|
||||||
regs[IP] <= regs[IP] + 1;
|
regs[IP] <= regs[IP] + 1;
|
||||||
write <= 0;
|
|
||||||
state <= S_DECODE;
|
state <= S_DECODE;
|
||||||
end
|
end
|
||||||
|
end
|
||||||
// state 2: read/decode opcode
|
// state 2: read/decode opcode
|
||||||
S_DECODE: begin
|
S_DECODE: begin
|
||||||
opcode <= data_in; // (only use opcode next cycle)
|
opcode <= data_in; // (only use opcode next cycle)
|
||||||
casez (data_in)
|
casez (data_in)
|
||||||
// 00000aaa 0++++bbb operation A+B->A
|
// 00000aaa0++++bbb operation A+B->A
|
||||||
16'b00000???0???????: begin
|
16'b00000???0???????: begin
|
||||||
aluop <= data_in[6:3];
|
aluop <= data_in[6:3];
|
||||||
state <= S_COMPUTE;
|
state <= S_COMPUTE;
|
||||||
end
|
end
|
||||||
// 00100aaa ######## load constant
|
// 00001aaa01+++bbb operation A+[B]->A
|
||||||
16'b00100???????????: begin
|
16'b00001???01??????: begin
|
||||||
regs[rdest] <= {8'b0, data_in[7:0]};
|
address <= regs[data_in[2:0]];
|
||||||
state <= S_SELECT;
|
aluop <= data_in[6:3];
|
||||||
|
state <= S_COMPUTE;
|
||||||
|
if (data_in[2:0] == SP)
|
||||||
|
regs[SP] <= regs[SP] + 1;
|
||||||
end
|
end
|
||||||
// 00101aaa ######## load memory
|
// 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
|
16'b00101???????????: begin
|
||||||
address <= {8'b0, data_in[7:0]};
|
address <= {8'b0, data_in[7:0]};
|
||||||
aluop <= `OP_LOAD_B;
|
aluop <= `OP_LOAD_B;
|
||||||
state <= S_COMPUTE;
|
state <= S_COMPUTE;
|
||||||
end
|
end
|
||||||
// 00110aaa ######## store memory
|
// 00110aaa######## store ZP memory
|
||||||
16'b00110???????????: begin
|
16'b00110???????????: begin
|
||||||
address <= {8'b0, data_in[7:0]};
|
address <= {8'b0, data_in[7:0]};
|
||||||
data_out <= regs[data_in[10:8]];
|
data_out <= regs[data_in[10:8]];
|
||||||
write <= 1;
|
write <= 1;
|
||||||
state <= S_SELECT;
|
state <= S_SELECT;
|
||||||
end
|
end
|
||||||
// 00001ttt ######## conditional branch
|
// 01001aaa#####bbb [B+#] -> A
|
||||||
16'b00001???????????: begin
|
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 (
|
if (
|
||||||
(data_in[8] && (data_in[10] == carry)) ||
|
(data_in[8] && (data_in[11] == carry)) ||
|
||||||
(data_in[9] && (data_in[10] == zero)))
|
(data_in[9] && (data_in[11] == zero)) ||
|
||||||
|
(data_in[10] && (data_in[11] == neg)))
|
||||||
begin
|
begin
|
||||||
// relative branch, sign extended
|
// relative branch, sign extended
|
||||||
regs[IP] <= regs[IP] + { {8{data_in[7]}}, data_in[7:0]};
|
regs[IP] <= regs[IP] + 16'($signed(data_in[7:0]));
|
||||||
end
|
end
|
||||||
state <= S_SELECT;
|
state <= S_SELECT;
|
||||||
end
|
end
|
||||||
@ -142,18 +207,22 @@ module test_CPU16_top(
|
|||||||
output write_enable,
|
output write_enable,
|
||||||
output [15:0] IP,
|
output [15:0] IP,
|
||||||
output zero,
|
output zero,
|
||||||
output carry
|
output carry,
|
||||||
|
output busy
|
||||||
);
|
);
|
||||||
|
|
||||||
reg [15:0] ram[0:65535];
|
reg [15:0] ram[0:65535];
|
||||||
reg [15:0] rom[0:65535];
|
reg [15:0] rom[0:255];
|
||||||
|
|
||||||
assign IP = cpu.regs[7];
|
assign IP = cpu.regs[7];
|
||||||
assign zero = cpu.zero;
|
assign zero = cpu.zero;
|
||||||
assign carry = cpu.carry;
|
assign carry = cpu.carry;
|
||||||
|
|
||||||
CPU16 cpu(.clk(clk),
|
CPU16 cpu(
|
||||||
|
.clk(clk),
|
||||||
.reset(reset),
|
.reset(reset),
|
||||||
|
.halt(0),
|
||||||
|
.busy(busy),
|
||||||
.address(address_bus),
|
.address(address_bus),
|
||||||
.data_in(to_cpu),
|
.data_in(to_cpu),
|
||||||
.data_out(from_cpu),
|
.data_out(from_cpu),
|
||||||
@ -168,7 +237,36 @@ module test_CPU16_top(
|
|||||||
if (address_bus[15] == 0)
|
if (address_bus[15] == 0)
|
||||||
to_cpu = ram[address_bus];
|
to_cpu = ram[address_bus];
|
||||||
else
|
else
|
||||||
to_cpu = rom[address_bus];
|
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
|
endmodule
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
`define ALU_H
|
`define ALU_H
|
||||||
|
|
||||||
// ALU operations
|
// ALU operations
|
||||||
`define OP_LOAD_A 4'h0
|
`define OP_ZERO 4'h0
|
||||||
`define OP_LOAD_B 4'h1
|
`define OP_LOAD_A 4'h1
|
||||||
`define OP_INC 4'h2
|
`define OP_INC 4'h2
|
||||||
`define OP_DEC 4'h3
|
`define OP_DEC 4'h3
|
||||||
`define OP_ASL 4'h4
|
`define OP_ASL 4'h4
|
||||||
@ -13,7 +13,7 @@
|
|||||||
`define OP_OR 4'h8
|
`define OP_OR 4'h8
|
||||||
`define OP_AND 4'h9
|
`define OP_AND 4'h9
|
||||||
`define OP_XOR 4'ha
|
`define OP_XOR 4'ha
|
||||||
`define OP_ZERO 4'hb
|
`define OP_LOAD_B 4'hb
|
||||||
`define OP_ADD 4'hc
|
`define OP_ADD 4'hc
|
||||||
`define OP_SUB 4'hd
|
`define OP_SUB 4'hd
|
||||||
`define OP_ADC 4'he
|
`define OP_ADC 4'he
|
||||||
@ -32,8 +32,8 @@ module ALU(A, B, Y, aluop, carry);
|
|||||||
always @(*)
|
always @(*)
|
||||||
case (aluop)
|
case (aluop)
|
||||||
// unary operations
|
// unary operations
|
||||||
|
`OP_ZERO: Y = 0;
|
||||||
`OP_LOAD_A: Y = {1'b0, A};
|
`OP_LOAD_A: Y = {1'b0, A};
|
||||||
`OP_LOAD_B: Y = {1'b0, B};
|
|
||||||
`OP_INC: Y = A + 1;
|
`OP_INC: Y = A + 1;
|
||||||
`OP_DEC: Y = A - 1;
|
`OP_DEC: Y = A - 1;
|
||||||
// unary operations that generate and/or use carry
|
// unary operations that generate and/or use carry
|
||||||
@ -45,7 +45,7 @@ module ALU(A, B, Y, aluop, carry);
|
|||||||
`OP_OR: Y = {1'b0, A | B};
|
`OP_OR: Y = {1'b0, A | B};
|
||||||
`OP_AND: Y = {1'b0, A & B};
|
`OP_AND: Y = {1'b0, A & B};
|
||||||
`OP_XOR: Y = {1'b0, A ^ B};
|
`OP_XOR: Y = {1'b0, A ^ B};
|
||||||
`OP_ZERO: Y = 0;
|
`OP_LOAD_B: Y = {1'b0, B};
|
||||||
// binary operations that generate and/or use carry
|
// binary operations that generate and/or use carry
|
||||||
`OP_ADD: Y = A + B;
|
`OP_ADD: Y = A + B;
|
||||||
`OP_SUB: Y = A - B;
|
`OP_SUB: Y = A - B;
|
||||||
|
@ -7,9 +7,10 @@ module digits10_case(digit, yofs, bits);
|
|||||||
|
|
||||||
input [3:0] digit;
|
input [3:0] digit;
|
||||||
input [2:0] yofs;
|
input [2:0] yofs;
|
||||||
output [4:0] bits;
|
output reg [4:0] bits;
|
||||||
|
|
||||||
wire [6:0] caseexpr = {digit,yofs};
|
wire [6:0] caseexpr = {digit,yofs};
|
||||||
|
|
||||||
always @(*)
|
always @(*)
|
||||||
case (caseexpr)/*{w:5,h:5,count:10}*/
|
case (caseexpr)/*{w:5,h:5,count:10}*/
|
||||||
7'o00: bits = 5'b11111;
|
7'o00: bits = 5'b11111;
|
||||||
|
38
presets/verilog/femto16.json
Normal file
38
presets/verilog/femto16.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name":"femto8",
|
||||||
|
"width":16,
|
||||||
|
"vars":{
|
||||||
|
"reg":{"bits":3, "toks":["ax", "bx", "cx", "dx", "ex", "fx", "sp", "ip"]},
|
||||||
|
"unop":{"bits":3, "toks":["zero","loada","inc","dec","asl","lsr","rol","ror"]},
|
||||||
|
"binop":{"bits":3, "toks":["or","and","xor","mov","add","sub","adc","sbb"]},
|
||||||
|
"imm8":{"bits":8},
|
||||||
|
"imm16":{"bits":16},
|
||||||
|
"rel8":{"bits":8, "iprel":true, "ipofs":1}
|
||||||
|
},
|
||||||
|
"rules":[
|
||||||
|
{"fmt":"~binop ~reg,~reg", "bits":["00000",1,"01",0,2]},
|
||||||
|
{"fmt":"~unop ~reg", "bits":["00000",1,"00",0,"000"]},
|
||||||
|
{"fmt":"~binop ~reg,[~reg]", "bits":["00001",1,"01",0,2]},
|
||||||
|
{"fmt":"mov [~reg],~reg", "bits":["01010",1,"00000",0]},
|
||||||
|
|
||||||
|
{"fmt":"mov ~reg,[~imm8]", "bits":["00101",0,1]},
|
||||||
|
{"fmt":"mov [~imm8],~reg", "bits":["00110",1,0]},
|
||||||
|
{"fmt":"~binop ~reg,#~imm8", "bits":["11",0,1,2]},
|
||||||
|
{"fmt":"~binop ~reg,@~imm16","bits":["00011",1,"01",0,"000",2]},
|
||||||
|
{"fmt":"~binop ~reg,[~imm16]", "bits":["01011",1,"01",0,"000",2]},
|
||||||
|
|
||||||
|
{"fmt":"push ~reg", "bits":["01010",0,"00000","110"]},
|
||||||
|
{"fmt":"pop ~reg", "bits":["01001",0,"00001","110"]},
|
||||||
|
{"fmt":"rts", "bits":["01001","111","00001","110"]},
|
||||||
|
{"fmt":"jsr ~reg", "bits":["01110","111","00",0,"110"]},
|
||||||
|
|
||||||
|
{"fmt":"bcc ~rel8", "bits":["10000001",0]},
|
||||||
|
{"fmt":"bcs ~rel8", "bits":["10001001",0]},
|
||||||
|
{"fmt":"bnz ~rel8", "bits":["10000010",0]},
|
||||||
|
{"fmt":"bz ~rel8", "bits":["10001010",0]},
|
||||||
|
{"fmt":"bpl ~rel8", "bits":["10000100",0]},
|
||||||
|
{"fmt":"bmi ~rel8", "bits":["10001100",0]},
|
||||||
|
|
||||||
|
{"fmt":"reset", "bits":["1011100011111111"]}
|
||||||
|
]
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
|
`undef EXT_INLINE_ASM
|
||||||
`include "hvsync_generator.v"
|
`include "hvsync_generator.v"
|
||||||
`include "sprite_bitmap.v"
|
|
||||||
`include "sprite_renderer.v"
|
|
||||||
`include "cpu8.v"
|
`include "cpu8.v"
|
||||||
|
`include "cpu16.v"
|
||||||
|
`define EXT_INLINE_ASM
|
||||||
|
|
||||||
// uncomment to see scope view
|
// uncomment to see scope view
|
||||||
//`define DEBUG
|
//`define DEBUG
|
||||||
@ -9,13 +10,11 @@
|
|||||||
module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
|
module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
|
||||||
address_bus, to_cpu, from_cpu, write_enable
|
address_bus, to_cpu, from_cpu, write_enable
|
||||||
`ifdef DEBUG
|
`ifdef DEBUG
|
||||||
, output [7:0] A
|
, output [15:0] IP
|
||||||
, output [7:0] B
|
|
||||||
, output [7:0] IP
|
|
||||||
, output carry
|
, output carry
|
||||||
, output zero
|
, output zero
|
||||||
`else
|
`else
|
||||||
,rgb
|
, rgb
|
||||||
`endif
|
`endif
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -26,9 +25,7 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
|
|||||||
wire [8:0] hpos;
|
wire [8:0] hpos;
|
||||||
wire [8:0] vpos;
|
wire [8:0] vpos;
|
||||||
`ifdef DEBUG
|
`ifdef DEBUG
|
||||||
assign IP = cpu.IP;
|
assign IP = cpu.regs[cpu.IP];
|
||||||
assign A = cpu.A;
|
|
||||||
assign B = cpu.B;
|
|
||||||
assign carry = cpu.carry;
|
assign carry = cpu.carry;
|
||||||
assign zero = cpu.zero;
|
assign zero = cpu.zero;
|
||||||
`else
|
`else
|
||||||
@ -38,18 +35,19 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
|
|||||||
parameter IN_HPOS = 8'b01000000;
|
parameter IN_HPOS = 8'b01000000;
|
||||||
parameter IN_VPOS = 8'b01000001;
|
parameter IN_VPOS = 8'b01000001;
|
||||||
parameter IN_FLAGS = 8'b01000010;
|
parameter IN_FLAGS = 8'b01000010;
|
||||||
parameter IN_VPU = 8'b01000011;
|
|
||||||
|
|
||||||
reg [7:0] ram[0:63];
|
reg [15:0] ram[0:32767];
|
||||||
reg [7:0] rom[0:127];
|
reg [15:0] rom[0:1023];
|
||||||
|
|
||||||
output wire [7:0] address_bus;
|
output wire [15:0] address_bus;
|
||||||
output reg [7:0] to_cpu;
|
output reg [15:0] to_cpu;
|
||||||
output wire [7:0] from_cpu;
|
output wire [15:0] from_cpu;
|
||||||
output wire write_enable;
|
output wire write_enable;
|
||||||
|
|
||||||
CPU cpu(.clk(clk),
|
CPU16 cpu(.clk(clk),
|
||||||
.reset(reset),
|
.reset(reset),
|
||||||
|
.hold(hold),
|
||||||
|
.busy(busy),
|
||||||
.address(address_bus),
|
.address(address_bus),
|
||||||
.data_in(to_cpu),
|
.data_in(to_cpu),
|
||||||
.data_out(from_cpu),
|
.data_out(from_cpu),
|
||||||
@ -57,47 +55,23 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
|
|||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
if (write_enable) begin
|
if (write_enable) begin
|
||||||
casez (address_bus)
|
ram[address_bus[14:0]] <= from_cpu;
|
||||||
// VPU lo byte
|
|
||||||
8'b0001000: begin
|
|
||||||
vpu_write[15:8] <= from_cpu;
|
|
||||||
end
|
|
||||||
// VPU hi byte
|
|
||||||
8'b0001001: begin
|
|
||||||
vpu_write[7:0] <= from_cpu;
|
|
||||||
end
|
|
||||||
// VPU write
|
|
||||||
8'b0001010: begin
|
|
||||||
vpu_ram[vpu_write] <= from_cpu[7:4];
|
|
||||||
vpu_ram[vpu_write+1] <= from_cpu[3:0];
|
|
||||||
vpu_write <= vpu_write + 2;
|
|
||||||
end
|
|
||||||
// VPU move
|
|
||||||
8'b0001011: begin
|
|
||||||
// sign extend
|
|
||||||
vpu_write <= {
|
|
||||||
vpu_write[15:8] + { {4{from_cpu[7]}}, from_cpu[7:4] },
|
|
||||||
vpu_write[7:0] + { {4{from_cpu[3]}}, from_cpu[3:0] }
|
|
||||||
};
|
|
||||||
end
|
|
||||||
default: ram[address_bus[5:0]] <= from_cpu;
|
|
||||||
endcase
|
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(*)
|
always @(*)
|
||||||
casez (address_bus)
|
if (address_bus[15])
|
||||||
// RAM
|
to_cpu = rom[address_bus[9:0]];
|
||||||
8'b00??????: to_cpu = ram[address_bus[5:0]];
|
else if (&address_bus[14:8]) begin
|
||||||
|
casez (address_bus[7:0])
|
||||||
// special read registers
|
// special read registers
|
||||||
IN_HPOS: to_cpu = hpos[7:0];
|
IN_HPOS: to_cpu = {8'b0, hpos[7:0]};
|
||||||
IN_VPOS: to_cpu = vpos[7:0];
|
IN_VPOS: to_cpu = {8'b0, vpos[7:0]};
|
||||||
IN_FLAGS: to_cpu = {3'b0,
|
IN_FLAGS: to_cpu = {11'b0,
|
||||||
vsync, hsync, vpaddle, hpaddle, display_on};
|
vsync, hsync, vpaddle, hpaddle, display_on};
|
||||||
IN_VPU: to_cpu = {vpu_ram[vpu_write], vpu_ram[vpu_write+1]};
|
default: to_cpu = 0;
|
||||||
// ROM
|
|
||||||
8'b1???????: to_cpu = rom[address_bus[7:0] + 128];
|
|
||||||
default: ;
|
|
||||||
endcase
|
endcase
|
||||||
|
end else
|
||||||
|
to_cpu = ram[address_bus[14:0]];
|
||||||
|
|
||||||
hvsync_generator hvsync_gen(
|
hvsync_generator hvsync_gen(
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
@ -109,38 +83,49 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
|
|||||||
.vpos(vpos)
|
.vpos(vpos)
|
||||||
);
|
);
|
||||||
|
|
||||||
reg [3:0] vpu_ram[0:65535];
|
// video DMA access
|
||||||
reg [15:0] vpu_read;
|
reg hold;
|
||||||
reg [15:0] vpu_write;
|
wire busy;
|
||||||
reg [3:0] rgb;
|
reg [15:0] vline[0:31]; // 32x16 bits = 256 4-color pixels
|
||||||
|
reg [4:0] vindex;
|
||||||
|
reg [15:0] vshift;
|
||||||
|
reg [3:0] palette[0:3] = '{0,1,4,7};
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
if (!hpos[8] && !vpos[8]) begin
|
// has CPU released the bus?
|
||||||
rgb <= vpu_ram[vpu_read];
|
if (busy) begin
|
||||||
vpu_read <= vpu_read + 1;
|
// write from main RAM -> scanline RAM
|
||||||
end else begin
|
vline[vindex] <= ram[{2'b10,vpos[7:0],vindex}];
|
||||||
|
// end of scanline read?
|
||||||
|
if (&vindex)
|
||||||
|
hold <= 0; // release CPU
|
||||||
|
vindex <= vindex + 1; // next address
|
||||||
|
end else if (hpos >= 256 && hpos < 256+4 && vpos < 240) begin
|
||||||
|
hold <= 1; // start DMA mode, hold CPU
|
||||||
|
end else if (!hpos[8] && vpos < 240) begin
|
||||||
|
// load next word from vline buffer
|
||||||
|
if (0 == hpos[2:0]) begin
|
||||||
|
vshift <= vline[vindex];
|
||||||
|
vindex <= vindex + 1;
|
||||||
|
end else
|
||||||
|
vshift <= vshift >> 2;
|
||||||
|
// decode scanline RAM to RGB output
|
||||||
|
rgb <= palette[vshift[1:0]];
|
||||||
|
end else
|
||||||
rgb <= 0;
|
rgb <= 0;
|
||||||
if (vpos[8])
|
|
||||||
vpu_read <= 0;
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
`ifdef EXT_INLINE_ASM
|
`ifdef EXT_INLINE_ASM
|
||||||
initial begin
|
initial begin
|
||||||
rom = '{
|
rom = '{
|
||||||
__asm
|
__asm
|
||||||
.arch femto8
|
.arch femto16
|
||||||
.org 128
|
.org 32768
|
||||||
.len 128
|
.len 1024
|
||||||
|
|
||||||
.define VPU_LO 8
|
.define IN_HPOS $7f00
|
||||||
.define VPU_HI 9
|
.define IN_VPOS $7f01
|
||||||
.define VPU_WRITE 10
|
.define IN_FLAGS $7f02
|
||||||
.define VPU_MOVE 11
|
|
||||||
|
|
||||||
.define IN_HPOS $40
|
|
||||||
.define IN_VPOS $41
|
|
||||||
.define IN_FLAGS $42
|
|
||||||
|
|
||||||
.define F_DISPLAY 1
|
.define F_DISPLAY 1
|
||||||
.define F_HPADDLE 2
|
.define F_HPADDLE 2
|
||||||
@ -149,31 +134,15 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
|
|||||||
.define F_VSYNC 16
|
.define F_VSYNC 16
|
||||||
|
|
||||||
Start:
|
Start:
|
||||||
zero A
|
mov ax,#0
|
||||||
sta VPU_LO
|
mov bx,ax
|
||||||
sta VPU_HI
|
Loop:
|
||||||
sta 0
|
xor ax,[bx]
|
||||||
DisplayLoop:
|
mov [bx],ax
|
||||||
zero B
|
inc bx
|
||||||
mov A,[b]
|
inc ax
|
||||||
sta VPU_WRITE
|
bnz Loop
|
||||||
sta VPU_MOVE
|
reset
|
||||||
sta VPU_WRITE
|
|
||||||
sta VPU_MOVE
|
|
||||||
sta VPU_WRITE
|
|
||||||
sta VPU_MOVE
|
|
||||||
lda #F_VSYNC
|
|
||||||
ldb #IN_FLAGS
|
|
||||||
and none,[B]
|
|
||||||
bz DisplayLoop
|
|
||||||
WaitVsync:
|
|
||||||
and none,[B]
|
|
||||||
bnz WaitVsync
|
|
||||||
zero B
|
|
||||||
mov A,[b]
|
|
||||||
inc A
|
|
||||||
sta 0
|
|
||||||
jmp DisplayLoop
|
|
||||||
__endasm
|
__endasm
|
||||||
};
|
};
|
||||||
end
|
end
|
||||||
|
@ -5,10 +5,10 @@ module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos);
|
|||||||
|
|
||||||
input clk;
|
input clk;
|
||||||
input reset;
|
input reset;
|
||||||
output hsync, vsync;
|
output reg hsync, vsync;
|
||||||
output display_on;
|
output display_on;
|
||||||
output [8:0] hpos;
|
output reg [8:0] hpos;
|
||||||
output [8:0] vpos;
|
output reg [8:0] vpos;
|
||||||
|
|
||||||
// constant declarations for TV-simulator sync parameters
|
// constant declarations for TV-simulator sync parameters
|
||||||
// horizontal
|
// horizontal
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
module player_stats(reset, score0, score1, lives, incscore, declives);
|
module player_stats(reset, score0, score1, lives, incscore, declives);
|
||||||
|
|
||||||
input reset;
|
input reset;
|
||||||
output [3:0] score0;
|
output reg [3:0] score0;
|
||||||
output [3:0] score1;
|
output reg [3:0] score1;
|
||||||
input incscore;
|
input incscore;
|
||||||
output [3:0] lives;
|
output reg [3:0] lives;
|
||||||
input declives;
|
input declives;
|
||||||
|
|
||||||
always @(posedge incscore or posedge reset)
|
always @(posedge incscore or posedge reset)
|
||||||
@ -45,8 +45,8 @@ module scoreboard_generator(score0, score1, lives, vpos, hpos, board_gfx);
|
|||||||
input [8:0] hpos;
|
input [8:0] hpos;
|
||||||
output board_gfx;
|
output board_gfx;
|
||||||
|
|
||||||
wire [3:0] score_digit;
|
reg [3:0] score_digit;
|
||||||
wire [4:0] score_bits;
|
reg [4:0] score_bits;
|
||||||
|
|
||||||
always @(*)
|
always @(*)
|
||||||
begin
|
begin
|
||||||
|
@ -81,6 +81,7 @@ module sprite_bitmap_top(clk, reset, hsync, vsync, rgb);
|
|||||||
wire [3:0] car_bit = car_sprite_xofs>=8 ?
|
wire [3:0] car_bit = car_sprite_xofs>=8 ?
|
||||||
15-car_sprite_xofs:
|
15-car_sprite_xofs:
|
||||||
car_sprite_xofs;
|
car_sprite_xofs;
|
||||||
|
|
||||||
wire car_gfx = car_sprite_bits[car_bit[2:0]];
|
wire car_gfx = car_sprite_bits[car_bit[2:0]];
|
||||||
|
|
||||||
wire r = display_on && car_gfx;
|
wire r = display_on && car_gfx;
|
||||||
|
@ -63,7 +63,7 @@ module sprite_multiple_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
|
|||||||
sprite_renderer enemy_renderer(
|
sprite_renderer enemy_renderer(
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.vstart(enemy_vstart),
|
.vstart(enemy_vstart),
|
||||||
.load(hpos == 257),
|
.load(hpos == 258),
|
||||||
.hstart(enemy_hstart),
|
.hstart(enemy_hstart),
|
||||||
.rom_addr(car_sprite_yofs),
|
.rom_addr(car_sprite_yofs),
|
||||||
.rom_bits(car_sprite_bits),
|
.rom_bits(car_sprite_bits),
|
||||||
|
@ -7,20 +7,24 @@
|
|||||||
module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
|
module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
|
||||||
gfx, in_progress);
|
gfx, in_progress);
|
||||||
|
|
||||||
input clk, vstart, load, hstart;
|
input clk;
|
||||||
output [3:0] rom_addr;
|
input vstart; // start drawing (top border)
|
||||||
input [7:0] rom_bits;
|
input load; // ok to load sprite data?
|
||||||
output gfx;
|
input hstart; // start drawing scanline (left border)
|
||||||
output in_progress;
|
output [3:0] rom_addr; // select ROM address
|
||||||
|
input [7:0] rom_bits; // input bits from ROM
|
||||||
|
output gfx; // output pixel
|
||||||
|
output in_progress; // 0 if waiting for vstart
|
||||||
|
|
||||||
assign in_progress = state != WAIT_FOR_VSTART;
|
assign in_progress = state != WAIT_FOR_VSTART;
|
||||||
|
|
||||||
reg [2:0] state;
|
reg [2:0] state; // current state #
|
||||||
reg [3:0] ycount;
|
reg [3:0] ycount; // number of scanlines drawn so far
|
||||||
reg [3:0] xcount;
|
reg [3:0] xcount; // number of horiz. pixels in this line
|
||||||
|
|
||||||
reg [7:0] outbits;
|
reg [7:0] outbits; // register to store bits from ROM
|
||||||
|
|
||||||
|
// states
|
||||||
localparam WAIT_FOR_VSTART = 0;
|
localparam WAIT_FOR_VSTART = 0;
|
||||||
localparam WAIT_FOR_LOAD = 1;
|
localparam WAIT_FOR_LOAD = 1;
|
||||||
localparam LOAD1_SETUP = 2;
|
localparam LOAD1_SETUP = 2;
|
||||||
@ -32,46 +36,49 @@ module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
|
|||||||
begin
|
begin
|
||||||
case (state)
|
case (state)
|
||||||
WAIT_FOR_VSTART: begin
|
WAIT_FOR_VSTART: begin
|
||||||
ycount <= 0;
|
ycount <= 0; // initialize vertical count
|
||||||
// set a default value (blank) for pixel output
|
gfx <= 0; // default pixel value (off)
|
||||||
// note: multiple non-blocking assignments are vendor-specific
|
// wait for vstart, then next state
|
||||||
gfx <= 0;
|
if (vstart)
|
||||||
if (vstart) state <= WAIT_FOR_LOAD;
|
state <= WAIT_FOR_LOAD;
|
||||||
end
|
end
|
||||||
WAIT_FOR_LOAD: begin
|
WAIT_FOR_LOAD: begin
|
||||||
xcount <= 0;
|
xcount <= 0; // initialize horiz. count
|
||||||
gfx <= 0;
|
gfx <= 0;
|
||||||
if (load) state <= LOAD1_SETUP;
|
// wait for load, then next state
|
||||||
|
if (load)
|
||||||
|
state <= LOAD1_SETUP;
|
||||||
end
|
end
|
||||||
LOAD1_SETUP: begin
|
LOAD1_SETUP: begin
|
||||||
rom_addr <= ycount;
|
rom_addr <= ycount; // load ROM address
|
||||||
gfx <= 0;
|
|
||||||
state <= LOAD1_FETCH;
|
state <= LOAD1_FETCH;
|
||||||
end
|
end
|
||||||
LOAD1_FETCH: begin
|
LOAD1_FETCH: begin
|
||||||
outbits[7:0] <= rom_bits;
|
outbits <= rom_bits; // latch bits from ROM
|
||||||
gfx <= 0;
|
|
||||||
state <= WAIT_FOR_HSTART;
|
state <= WAIT_FOR_HSTART;
|
||||||
end
|
end
|
||||||
WAIT_FOR_HSTART: begin
|
WAIT_FOR_HSTART: begin
|
||||||
if (hstart) state <= DRAW;
|
// wait for hstart, then start drawing
|
||||||
gfx <= 0;
|
if (hstart)
|
||||||
|
state <= DRAW;
|
||||||
end
|
end
|
||||||
DRAW: begin
|
DRAW: begin
|
||||||
// mirror graphics left/right
|
// get pixel, mirroring graphics left/right
|
||||||
gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]];
|
gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]];
|
||||||
xcount <= xcount + 1;
|
xcount <= xcount + 1;
|
||||||
|
// finished drawing horizontal slice?
|
||||||
if (xcount == 15) begin // pre-increment value
|
if (xcount == 15) begin // pre-increment value
|
||||||
ycount <= ycount + 1;
|
ycount <= ycount + 1;
|
||||||
|
// finished drawing sprite?
|
||||||
if (ycount == 15) // pre-increment value
|
if (ycount == 15) // pre-increment value
|
||||||
state <= WAIT_FOR_VSTART; // done drawing sprite
|
state <= WAIT_FOR_VSTART; // done drawing sprite
|
||||||
else
|
else
|
||||||
state <= WAIT_FOR_LOAD; // done drawing this scanline
|
state <= WAIT_FOR_LOAD; // done drawing this scanline
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
// unknown state -- reset
|
||||||
default: begin
|
default: begin
|
||||||
state <= 0; // TODO: reset
|
state <= WAIT_FOR_VSTART;
|
||||||
gfx <= 0;
|
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
@ -105,33 +112,33 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
|
|||||||
.vpos(vpos)
|
.vpos(vpos)
|
||||||
);
|
);
|
||||||
|
|
||||||
wire [3:0] car_sprite_yofs;
|
wire [3:0] car_sprite_addr;
|
||||||
wire [7:0] car_sprite_bits;
|
wire [7:0] car_sprite_bits;
|
||||||
|
|
||||||
car_bitmap car(
|
car_bitmap car(
|
||||||
.yofs(car_sprite_yofs),
|
.yofs(car_sprite_addr),
|
||||||
.bits(car_sprite_bits));
|
.bits(car_sprite_bits));
|
||||||
|
|
||||||
wire vstart = {1'd0,player_y} == vpos;
|
wire vstart = {1'd0,player_y} == vpos;
|
||||||
wire hstart = {1'd0,player_x} == hpos;
|
wire hstart = {1'd0,player_x} == hpos;
|
||||||
wire car_gfx;
|
wire car_gfx;
|
||||||
wire unused;
|
wire in_progress;
|
||||||
|
|
||||||
sprite_renderer renderer(
|
sprite_renderer renderer(
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.vstart(vstart),
|
.vstart(vstart),
|
||||||
.load(hsync),
|
.load(hsync),
|
||||||
.hstart(hstart),
|
.hstart(hstart),
|
||||||
.rom_addr(car_sprite_yofs),
|
.rom_addr(car_sprite_addr),
|
||||||
.rom_bits(car_sprite_bits),
|
.rom_bits(car_sprite_bits),
|
||||||
.gfx(car_gfx),
|
.gfx(car_gfx),
|
||||||
.in_progress(unused));
|
.in_progress(in_progress));
|
||||||
|
|
||||||
always @(posedge hsync)
|
always @(posedge hpaddle)
|
||||||
begin
|
paddle_x <= vpos[7:0];
|
||||||
if (!hpaddle) paddle_x <= vpos[7:0];
|
|
||||||
if (!vpaddle) paddle_y <= vpos[7:0];
|
always @(posedge vpaddle)
|
||||||
end
|
paddle_y <= vpos[7:0];
|
||||||
|
|
||||||
always @(posedge vsync)
|
always @(posedge vsync)
|
||||||
begin
|
begin
|
||||||
@ -141,7 +148,7 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
|
|||||||
|
|
||||||
wire r = display_on && car_gfx;
|
wire r = display_on && car_gfx;
|
||||||
wire g = display_on && car_gfx;
|
wire g = display_on && car_gfx;
|
||||||
wire b = display_on && car_gfx;
|
wire b = display_on && in_progress;
|
||||||
assign rgb = {b,g,r};
|
assign rgb = {b,g,r};
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -8,7 +8,7 @@ module tank_bitmap(addr, bits);
|
|||||||
input [7:0] addr;
|
input [7:0] addr;
|
||||||
output [7:0] bits;
|
output [7:0] bits;
|
||||||
|
|
||||||
reg [15:0] bitarray[256];
|
reg [15:0] bitarray[0:255];
|
||||||
|
|
||||||
assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0];
|
assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0];
|
||||||
|
|
||||||
@ -109,7 +109,9 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits,
|
|||||||
output [4:0] rom_addr;
|
output [4:0] rom_addr;
|
||||||
input [7:0] rom_bits;
|
input [7:0] rom_bits;
|
||||||
output gfx;
|
output gfx;
|
||||||
output busy = state != WAIT_FOR_VSTART;
|
output busy;
|
||||||
|
|
||||||
|
assign busy = state != WAIT_FOR_VSTART;
|
||||||
|
|
||||||
reg [2:0] state;
|
reg [2:0] state;
|
||||||
reg [3:0] ycount;
|
reg [3:0] ycount;
|
||||||
@ -178,6 +180,7 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits,
|
|||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module rotation_selector(rotation, bitmap_num, hmirror, vmirror);
|
module rotation_selector(rotation, bitmap_num, hmirror, vmirror);
|
||||||
|
|
||||||
input [3:0] rotation;
|
input [3:0] rotation;
|
||||||
output [2:0] bitmap_num;
|
output [2:0] bitmap_num;
|
||||||
output hmirror, vmirror;
|
output hmirror, vmirror;
|
||||||
@ -208,23 +211,6 @@ module rotation_selector(rotation, bitmap_num, hmirror, vmirror);
|
|||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
function signed [7:0] sin_16x4;
|
|
||||||
input [3:0] in;
|
|
||||||
integer y;
|
|
||||||
case (in[1:0])
|
|
||||||
0: y = 0;
|
|
||||||
1: y = 3;
|
|
||||||
2: y = 5;
|
|
||||||
3: y = 6;
|
|
||||||
endcase
|
|
||||||
case (in[3:2])
|
|
||||||
0: sin_16x4 = 8'(y);
|
|
||||||
1: sin_16x4 = 8'(7-y);
|
|
||||||
2: sin_16x4 = 8'(-y);
|
|
||||||
3: sin_16x4 = 8'(y-7);
|
|
||||||
endcase
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
|
module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
|
||||||
sprite_addr, sprite_bits, gfx,
|
sprite_addr, sprite_bits, gfx,
|
||||||
playfield,
|
playfield,
|
||||||
@ -305,9 +291,33 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// set if collision; cleared at vsync
|
||||||
reg collision_detected;
|
reg collision_detected;
|
||||||
always @(posedge collision_gfx or posedge vsync or posedge reset)
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (collision_gfx)
|
||||||
collision_detected <= collision_gfx;
|
collision_detected <= collision_gfx;
|
||||||
|
else if (vsync)
|
||||||
|
collision_detected <= 0;
|
||||||
|
|
||||||
|
// sine lookup (4 bits input, 4 signed bits output)
|
||||||
|
|
||||||
|
function signed [3:0] sin_16x4;
|
||||||
|
input [3:0] in;
|
||||||
|
integer y;
|
||||||
|
case (in[1:0])
|
||||||
|
0: y = 0;
|
||||||
|
1: y = 3;
|
||||||
|
2: y = 5;
|
||||||
|
3: y = 6;
|
||||||
|
endcase
|
||||||
|
case (in[3:2])
|
||||||
|
0: sin_16x4 = 4'(y);
|
||||||
|
1: sin_16x4 = 4'(7-y);
|
||||||
|
2: sin_16x4 = 4'(-y);
|
||||||
|
3: sin_16x4 = 4'(y-7);
|
||||||
|
endcase
|
||||||
|
endfunction
|
||||||
|
|
||||||
always @(posedge hsync or posedge reset)
|
always @(posedge hsync or posedge reset)
|
||||||
if (reset) begin
|
if (reset) begin
|
||||||
|
@ -180,13 +180,13 @@ var VerilogPlatform = function(mainElement, options) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var video, audio;
|
var video, audio;
|
||||||
var useAudio = false;
|
var useAudio = false;
|
||||||
var videoWidth = 256+16;
|
var videoWidth = 256+20;
|
||||||
var videoHeight = 240+16;
|
var videoHeight = 240+20;
|
||||||
var maxVideoBlankLines = 80;
|
var maxVideoBlankLines = 40; // vertical hold
|
||||||
var idata, timer;
|
var idata, timer;
|
||||||
var gen;
|
var gen;
|
||||||
var frameRate = 60;
|
var frameRate = 60;
|
||||||
var AUDIO_FREQ = (256+23+7+23)*262*60; // 4857480
|
var AUDIO_FREQ = (256+23+7+23)*262*60; // 4857480 Hz
|
||||||
var current_output;
|
var current_output;
|
||||||
var paddle_x = 0;
|
var paddle_x = 0;
|
||||||
var paddle_y = 0;
|
var paddle_y = 0;
|
||||||
@ -235,6 +235,7 @@ var VerilogPlatform = function(mainElement, options) {
|
|||||||
if (inspect_obj && inspect_sym) {
|
if (inspect_obj && inspect_sym) {
|
||||||
var COLOR_BIT_OFF = 0xffff3333;
|
var COLOR_BIT_OFF = 0xffff3333;
|
||||||
var COLOR_BIT_ON = 0xffffffff;
|
var COLOR_BIT_ON = 0xffffffff;
|
||||||
|
/*
|
||||||
for (var y=0; y<videoHeight; y++) {
|
for (var y=0; y<videoHeight; y++) {
|
||||||
var val = inspect_data[y * videoWidth];
|
var val = inspect_data[y * videoWidth];
|
||||||
var i = y * videoWidth + 16;
|
var i = y * videoWidth + 16;
|
||||||
@ -244,6 +245,14 @@ var VerilogPlatform = function(mainElement, options) {
|
|||||||
val >>= 1;
|
val >>= 1;
|
||||||
} while (val != 0);
|
} while (val != 0);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
var i = 0;
|
||||||
|
for (var y=0; y<videoHeight; y++) {
|
||||||
|
for (var x=0; x<videoWidth; x++) {
|
||||||
|
var val = inspect_data[i];
|
||||||
|
idata[i++] = (val & 1) ? COLOR_BIT_ON : COLOR_BIT_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +450,6 @@ var VerilogPlatform = function(mainElement, options) {
|
|||||||
});
|
});
|
||||||
audio = new SampleAudio(AUDIO_FREQ);
|
audio = new SampleAudio(AUDIO_FREQ);
|
||||||
idata = video.getFrameData();
|
idata = video.getFrameData();
|
||||||
// TODO: 15.7 kHz?
|
|
||||||
timer = new AnimationTimer(frameRate, function() {
|
timer = new AnimationTimer(frameRate, function() {
|
||||||
if (!self.isRunning())
|
if (!self.isRunning())
|
||||||
return;
|
return;
|
||||||
|
@ -534,7 +534,7 @@ function setCompileOutput(data) {
|
|||||||
editor.setGutterMarker(info.line-1, "gutter-offset", textel);
|
editor.setGutterMarker(info.line-1, "gutter-offset", textel);
|
||||||
}
|
}
|
||||||
if (info.insns) {
|
if (info.insns) {
|
||||||
var insnstr = info.insns.length > 8 ? ("...") : info.insns;
|
var insnstr = info.insns.length > 9 ? ("...") : info.insns;
|
||||||
var textel = document.createTextNode(insnstr);
|
var textel = document.createTextNode(insnstr);
|
||||||
editor.setGutterMarker(info.line-1, "gutter-bytes", textel);
|
editor.setGutterMarker(info.line-1, "gutter-bytes", textel);
|
||||||
if (info.iscode) {
|
if (info.iscode) {
|
||||||
|
@ -70,16 +70,18 @@ var Assembler = function(spec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function preprocessRules() {
|
function preprocessRules() {
|
||||||
|
if (spec.width)
|
||||||
|
width = spec.width|0;
|
||||||
for (var i=0; i<spec.rules.length; i++)
|
for (var i=0; i<spec.rules.length; i++)
|
||||||
rule2regex(spec.rules[i], spec.vars);
|
rule2regex(spec.rules[i], spec.vars);
|
||||||
}
|
}
|
||||||
if (spec) preprocessRules();
|
if (spec) preprocessRules();
|
||||||
|
|
||||||
function warning(msg) {
|
function warning(msg, line) {
|
||||||
errors.push({msg:msg, line:linenum});
|
errors.push({msg:msg, line:line?line:linenum});
|
||||||
}
|
}
|
||||||
function fatal(msg) {
|
function fatal(msg, line) {
|
||||||
warning(msg);
|
warning(msg, line);
|
||||||
aborted = true;
|
aborted = true;
|
||||||
}
|
}
|
||||||
function hex(v, nd) {
|
function hex(v, nd) {
|
||||||
@ -106,7 +108,8 @@ var Assembler = function(spec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseConst(s) {
|
function parseConst(s, nbits) {
|
||||||
|
// TODO: check bit length
|
||||||
if (!s.length)
|
if (!s.length)
|
||||||
return s;
|
return s;
|
||||||
else if (s.startsWith("$"))
|
else if (s.startsWith("$"))
|
||||||
@ -128,8 +131,7 @@ var Assembler = function(spec) {
|
|||||||
var id = m[b+1];
|
var id = m[b+1];
|
||||||
var v = spec.vars[rule.varlist[b]];
|
var v = spec.vars[rule.varlist[b]];
|
||||||
if (!v) {
|
if (!v) {
|
||||||
warning("Could not find matching identifier for '" + m[0] + "'");
|
return {error:"Could not find matching identifier for '" + m[0] + "'"};
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
n = v.bits;
|
n = v.bits;
|
||||||
if (v.toks) {
|
if (v.toks) {
|
||||||
@ -137,7 +139,7 @@ var Assembler = function(spec) {
|
|||||||
if (x < 0)
|
if (x < 0)
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
x = parseConst(id);
|
x = parseConst(id, n);
|
||||||
// is it a label? add fixup
|
// is it a label? add fixup
|
||||||
if (isNaN(x)) {
|
if (isNaN(x)) {
|
||||||
fixups.push({sym:id, ofs:ip, bitlen:n, bitofs:oplen, line:linenum, iprel:!!v.iprel, ipofs:(v.ipofs+0)});
|
fixups.push({sym:id, ofs:ip, bitlen:n, bitofs:oplen, line:linenum, iprel:!!v.iprel, ipofs:(v.ipofs+0)});
|
||||||
@ -147,7 +149,7 @@ var Assembler = function(spec) {
|
|||||||
}
|
}
|
||||||
var mask = (1<<n)-1;
|
var mask = (1<<n)-1;
|
||||||
if ((x&mask) != x)
|
if ((x&mask) != x)
|
||||||
warning("Value " + x + " could not fit in " + n + " bits");
|
return {error:"Value " + x + " does not fit in " + n + " bits"};
|
||||||
opcode = (opcode << n) | x;
|
opcode = (opcode << n) | x;
|
||||||
oplen += n;
|
oplen += n;
|
||||||
}
|
}
|
||||||
@ -206,18 +208,21 @@ var Assembler = function(spec) {
|
|||||||
return; // empty line
|
return; // empty line
|
||||||
// look at each rule in order
|
// look at each rule in order
|
||||||
if (!spec) { fatal("Need to load .spec first"); return; }
|
if (!spec) { fatal("Need to load .spec first"); return; }
|
||||||
|
var lastError;
|
||||||
for (var i=0; i<spec.rules.length; i++) {
|
for (var i=0; i<spec.rules.length; i++) {
|
||||||
var rule = spec.rules[i];
|
var rule = spec.rules[i];
|
||||||
var m = rule.re.exec(line);
|
var m = rule.re.exec(line);
|
||||||
if (m) {
|
if (m) {
|
||||||
var result = self.buildInstruction(rule, m);
|
var result = self.buildInstruction(rule, m);
|
||||||
if (result) {
|
if (result && result.nbits) {
|
||||||
addBytes(result);
|
addBytes(result);
|
||||||
return result;
|
return result;
|
||||||
|
} else if (result && result.error) {
|
||||||
|
lastError = result.error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
warning("Could not decode instruction: " + line);
|
warning(lastError ? lastError : ("Could not decode instruction: " + line));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finish = function() {
|
self.finish = function() {
|
||||||
@ -226,15 +231,18 @@ var Assembler = function(spec) {
|
|||||||
var fix = fixups[i];
|
var fix = fixups[i];
|
||||||
var sym = symbols[fix.sym];
|
var sym = symbols[fix.sym];
|
||||||
if (sym) {
|
if (sym) {
|
||||||
var ofs = fix.ofs + (fix.bitofs>>3);
|
var ofs = fix.ofs + Math.floor(fix.bitofs/width);
|
||||||
var shift = fix.bitofs&7;
|
var shift = fix.bitofs & (width-1);
|
||||||
var mask = ((1<<fix.bitlen)-1);
|
var mask = ((1<<fix.bitlen)-1);
|
||||||
var value = parseConst(sym.value);
|
var value = parseConst(sym.value, fix.bitlen);
|
||||||
if (fix.iprel) value -= fix.ofs + fix.ipofs;
|
if (fix.iprel)
|
||||||
|
value -= fix.ofs + fix.ipofs;
|
||||||
|
if (value > mask || value < -mask)
|
||||||
|
warning("Symbol " + fix.sym + " (" + value + ") does not fit in " + fix.bitlen + " bits", fix.line);
|
||||||
value &= mask;
|
value &= mask;
|
||||||
// TODO: check range
|
// TODO: check range
|
||||||
// TODO: span multiple words?
|
// TODO: span multiple words?
|
||||||
outwords[ofs - origin] ^= value;
|
outwords[ofs - origin] ^= value; // TODO: << shift?
|
||||||
} else {
|
} else {
|
||||||
warning("Symbol '" + fix.sym + "' not found");
|
warning("Symbol '" + fix.sym + "' not found");
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,12 @@ describe('Assemble', function() {
|
|||||||
.define F_VSYNC 16
|
.define F_VSYNC 16
|
||||||
|
|
||||||
Start:
|
Start:
|
||||||
zero A
|
zero A ; comment
|
||||||
sta VPU_LO
|
sta VPU_LO
|
||||||
sta VPU_HI
|
sta VPU_HI
|
||||||
sta 0
|
sta 0
|
||||||
DisplayLoop:
|
|
||||||
zero B
|
DisplayLoop:zero B
|
||||||
mov A,[b]
|
mov A,[b]
|
||||||
sta VPU_WRITE
|
sta VPU_WRITE
|
||||||
sta VPU_MOVE
|
sta VPU_MOVE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user