moved around ALU ops, 16-bit cpu, reg/wire

This commit is contained in:
Steven Hugg 2018-02-18 18:19:20 -06:00
parent f6d320a05b
commit 20ddb8a11f
16 changed files with 375 additions and 235 deletions

View File

@ -3,7 +3,7 @@
module seven_segment_decoder(digit, segments);
input [3:0] digit;
output [6:0] segments;
output reg [6:0] segments;
always @(*)
case(digit)
@ -26,7 +26,7 @@ module segments_to_bitmap(segments, line, bits);
input [6:0] segments;
input [2:0] line;
output [4:0] bits;
output reg [4:0] bits;
always @(*)
case (line)

View File

@ -5,20 +5,25 @@
/*
00000aaa 0++++bbb operation A+B->A
00001ttt ######## conditional branch
00100aaa ######## load constant
00101aaa ######## load memory
00110aaa ######## store memory
01000aaa #####bbb load [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+#]
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
*/
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 reset;
input halt;
output busy;
output [15:0] address;
input [15:0] data_in;
output [15:0] data_out;
@ -37,26 +42,30 @@ module CPU16(clk, reset, address, data_in, data_out, write);
reg [3:0] aluop;
wire [2:0] rdest = opcode[10:8];
wire [2:0] rsrc = opcode[2:0];
wire Bload = opcode[11]; // TODO
wire Bconst = opcode[15]; // TODO
wire Bload = opcode[11]; // TODO
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(regs[rsrc]),
.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 <= 0;
write <= 0;
state <= S_RESET;
busy <= 1;
end else begin
case (state)
// state 0: reset
@ -67,46 +76,102 @@ module CPU16(clk, reset, address, data_in, data_out, write);
end
// state 1: select opcode address
S_SELECT: begin
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
write <= 0;
state <= S_DECODE;
if (halt) 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
opcode <= data_in; // (only use opcode next cycle)
casez (data_in)
// 00000aaa 0++++bbb operation A+B->A
// 00000aaa0++++bbb operation A+B->A
16'b00000???0???????: begin
aluop <= data_in[6:3];
state <= S_COMPUTE;
end
// 00100aaa ######## load constant
16'b00100???????????: begin
regs[rdest] <= {8'b0, data_in[7:0]};
state <= S_SELECT;
// 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
// 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
address <= {8'b0, data_in[7:0]};
aluop <= `OP_LOAD_B;
state <= S_COMPUTE;
end
// 00110aaa ######## store memory
// 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
// 00001ttt ######## conditional branch
16'b00001???????????: begin
// 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[10] == carry)) ||
(data_in[9] && (data_in[10] == zero)))
(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] + { {8{data_in[7]}}, data_in[7:0]};
regs[IP] <= regs[IP] + 16'($signed(data_in[7:0]));
end
state <= S_SELECT;
end
@ -142,18 +207,22 @@ module test_CPU16_top(
output write_enable,
output [15:0] IP,
output zero,
output carry
output carry,
output busy
);
reg [15:0] ram[0:65535];
reg [15:0] rom[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),
CPU16 cpu(
.clk(clk),
.reset(reset),
.halt(0),
.busy(busy),
.address(address_bus),
.data_in(to_cpu),
.data_out(from_cpu),
@ -168,8 +237,37 @@ module test_CPU16_top(
if (address_bus[15] == 0)
to_cpu = ram[address_bus];
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
`endif

View File

@ -2,8 +2,8 @@
`define ALU_H
// ALU operations
`define OP_LOAD_A 4'h0
`define OP_LOAD_B 4'h1
`define OP_ZERO 4'h0
`define OP_LOAD_A 4'h1
`define OP_INC 4'h2
`define OP_DEC 4'h3
`define OP_ASL 4'h4
@ -13,7 +13,7 @@
`define OP_OR 4'h8
`define OP_AND 4'h9
`define OP_XOR 4'ha
`define OP_ZERO 4'hb
`define OP_LOAD_B 4'hb
`define OP_ADD 4'hc
`define OP_SUB 4'hd
`define OP_ADC 4'he
@ -32,8 +32,8 @@ module ALU(A, B, Y, aluop, carry);
always @(*)
case (aluop)
// unary operations
`OP_ZERO: Y = 0;
`OP_LOAD_A: Y = {1'b0, A};
`OP_LOAD_B: Y = {1'b0, B};
`OP_INC: Y = A + 1;
`OP_DEC: Y = A - 1;
// 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_AND: 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
`OP_ADD: Y = A + B;
`OP_SUB: Y = A - B;

View File

@ -7,9 +7,10 @@ module digits10_case(digit, yofs, bits);
input [3:0] digit;
input [2:0] yofs;
output [4:0] bits;
output reg [4:0] bits;
wire [6:0] caseexpr = {digit,yofs};
always @(*)
case (caseexpr)/*{w:5,h:5,count:10}*/
7'o00: bits = 5'b11111;

View 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"]}
]
}

View File

@ -1,7 +1,8 @@
`undef EXT_INLINE_ASM
`include "hvsync_generator.v"
`include "sprite_bitmap.v"
`include "sprite_renderer.v"
`include "cpu8.v"
`include "cpu16.v"
`define EXT_INLINE_ASM
// uncomment to see scope view
//`define DEBUG
@ -9,13 +10,11 @@
module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
address_bus, to_cpu, from_cpu, write_enable
`ifdef DEBUG
, output [7:0] A
, output [7:0] B
, output [7:0] IP
, output [15:0] IP
, output carry
, output zero
`else
,rgb
, rgb
`endif
);
@ -26,9 +25,7 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
wire [8:0] hpos;
wire [8:0] vpos;
`ifdef DEBUG
assign IP = cpu.IP;
assign A = cpu.A;
assign B = cpu.B;
assign IP = cpu.regs[cpu.IP];
assign carry = cpu.carry;
assign zero = cpu.zero;
`else
@ -38,18 +35,19 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
parameter IN_HPOS = 8'b01000000;
parameter IN_VPOS = 8'b01000001;
parameter IN_FLAGS = 8'b01000010;
parameter IN_VPU = 8'b01000011;
reg [7:0] ram[0:63];
reg [7:0] rom[0:127];
reg [15:0] ram[0:32767];
reg [15:0] rom[0:1023];
output wire [7:0] address_bus;
output reg [7:0] to_cpu;
output wire [7:0] from_cpu;
output wire [15:0] address_bus;
output reg [15:0] to_cpu;
output wire [15:0] from_cpu;
output wire write_enable;
CPU cpu(.clk(clk),
CPU16 cpu(.clk(clk),
.reset(reset),
.hold(hold),
.busy(busy),
.address(address_bus),
.data_in(to_cpu),
.data_out(from_cpu),
@ -57,47 +55,23 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
always @(posedge clk)
if (write_enable) begin
casez (address_bus)
// 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
ram[address_bus[14:0]] <= from_cpu;
end
always @(*)
casez (address_bus)
// RAM
8'b00??????: to_cpu = ram[address_bus[5:0]];
// special read registers
IN_HPOS: to_cpu = hpos[7:0];
IN_VPOS: to_cpu = vpos[7:0];
IN_FLAGS: to_cpu = {3'b0,
vsync, hsync, vpaddle, hpaddle, display_on};
IN_VPU: to_cpu = {vpu_ram[vpu_write], vpu_ram[vpu_write+1]};
// ROM
8'b1???????: to_cpu = rom[address_bus[7:0] + 128];
default: ;
endcase
if (address_bus[15])
to_cpu = rom[address_bus[9:0]];
else if (&address_bus[14:8]) begin
casez (address_bus[7:0])
// special read registers
IN_HPOS: to_cpu = {8'b0, hpos[7:0]};
IN_VPOS: to_cpu = {8'b0, vpos[7:0]};
IN_FLAGS: to_cpu = {11'b0,
vsync, hsync, vpaddle, hpaddle, display_on};
default: to_cpu = 0;
endcase
end else
to_cpu = ram[address_bus[14:0]];
hvsync_generator hvsync_gen(
.clk(clk),
@ -108,72 +82,67 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.hpos(hpos),
.vpos(vpos)
);
reg [3:0] vpu_ram[0:65535];
reg [15:0] vpu_read;
reg [15:0] vpu_write;
reg [3:0] rgb;
// video DMA access
reg hold;
wire busy;
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
if (!hpos[8] && !vpos[8]) begin
rgb <= vpu_ram[vpu_read];
vpu_read <= vpu_read + 1;
end else begin
// has CPU released the bus?
if (busy) begin
// write from main RAM -> scanline RAM
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;
if (vpos[8])
vpu_read <= 0;
end
end
`ifdef EXT_INLINE_ASM
initial begin
rom = '{
__asm
.arch femto8
.org 128
.len 128
.arch femto16
.org 32768
.len 1024
.define VPU_LO 8
.define VPU_HI 9
.define VPU_WRITE 10
.define VPU_MOVE 11
.define IN_HPOS $40
.define IN_VPOS $41
.define IN_FLAGS $42
.define IN_HPOS $7f00
.define IN_VPOS $7f01
.define IN_FLAGS $7f02
.define F_DISPLAY 1
.define F_HPADDLE 2
.define F_VPADDLE 4
.define F_HSYNC 8
.define F_VSYNC 16
Start:
zero A
sta VPU_LO
sta VPU_HI
sta 0
DisplayLoop:
zero B
mov A,[b]
sta VPU_WRITE
sta VPU_MOVE
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
mov ax,#0
mov bx,ax
Loop:
xor ax,[bx]
mov [bx],ax
inc bx
inc ax
bnz Loop
reset
__endasm
};
end

View File

@ -5,10 +5,10 @@ module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos);
input clk;
input reset;
output hsync, vsync;
output reg hsync, vsync;
output display_on;
output [8:0] hpos;
output [8:0] vpos;
output reg [8:0] hpos;
output reg [8:0] vpos;
// constant declarations for TV-simulator sync parameters
// horizontal

View File

@ -7,10 +7,10 @@
module player_stats(reset, score0, score1, lives, incscore, declives);
input reset;
output [3:0] score0;
output [3:0] score1;
output reg [3:0] score0;
output reg [3:0] score1;
input incscore;
output [3:0] lives;
output reg [3:0] lives;
input declives;
always @(posedge incscore or posedge reset)
@ -45,8 +45,8 @@ module scoreboard_generator(score0, score1, lives, vpos, hpos, board_gfx);
input [8:0] hpos;
output board_gfx;
wire [3:0] score_digit;
wire [4:0] score_bits;
reg [3:0] score_digit;
reg [4:0] score_bits;
always @(*)
begin

View File

@ -81,6 +81,7 @@ module sprite_bitmap_top(clk, reset, hsync, vsync, rgb);
wire [3:0] car_bit = car_sprite_xofs>=8 ?
15-car_sprite_xofs:
car_sprite_xofs;
wire car_gfx = car_sprite_bits[car_bit[2:0]];
wire r = display_on && car_gfx;

View File

@ -63,7 +63,7 @@ module sprite_multiple_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
sprite_renderer enemy_renderer(
.clk(clk),
.vstart(enemy_vstart),
.load(hpos == 257),
.load(hpos == 258),
.hstart(enemy_hstart),
.rom_addr(car_sprite_yofs),
.rom_bits(car_sprite_bits),

View File

@ -7,20 +7,24 @@
module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
gfx, in_progress);
input clk, vstart, load, hstart;
output [3:0] rom_addr;
input [7:0] rom_bits;
output gfx;
output in_progress;
input clk;
input vstart; // start drawing (top border)
input load; // ok to load sprite data?
input hstart; // start drawing scanline (left border)
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;
reg [2:0] state;
reg [3:0] ycount;
reg [3:0] xcount;
reg [2:0] state; // current state #
reg [3:0] ycount; // number of scanlines drawn so far
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_LOAD = 1;
localparam LOAD1_SETUP = 2;
@ -32,46 +36,49 @@ module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
begin
case (state)
WAIT_FOR_VSTART: begin
ycount <= 0;
// set a default value (blank) for pixel output
// note: multiple non-blocking assignments are vendor-specific
gfx <= 0;
if (vstart) state <= WAIT_FOR_LOAD;
ycount <= 0; // initialize vertical count
gfx <= 0; // default pixel value (off)
// wait for vstart, then next state
if (vstart)
state <= WAIT_FOR_LOAD;
end
WAIT_FOR_LOAD: begin
xcount <= 0;
xcount <= 0; // initialize horiz. count
gfx <= 0;
if (load) state <= LOAD1_SETUP;
// wait for load, then next state
if (load)
state <= LOAD1_SETUP;
end
LOAD1_SETUP: begin
rom_addr <= ycount;
gfx <= 0;
rom_addr <= ycount; // load ROM address
state <= LOAD1_FETCH;
end
LOAD1_FETCH: begin
outbits[7:0] <= rom_bits;
gfx <= 0;
outbits <= rom_bits; // latch bits from ROM
state <= WAIT_FOR_HSTART;
end
WAIT_FOR_HSTART: begin
if (hstart) state <= DRAW;
gfx <= 0;
// wait for hstart, then start drawing
if (hstart)
state <= DRAW;
end
DRAW: begin
// mirror graphics left/right
// get pixel, mirroring graphics left/right
gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]];
xcount <= xcount + 1;
// finished drawing horizontal slice?
if (xcount == 15) begin // pre-increment value
ycount <= ycount + 1;
// finished drawing sprite?
if (ycount == 15) // pre-increment value
state <= WAIT_FOR_VSTART; // done drawing sprite
else
state <= WAIT_FOR_LOAD; // done drawing this scanline
end
end
// unknown state -- reset
default: begin
state <= 0; // TODO: reset
gfx <= 0;
state <= WAIT_FOR_VSTART;
end
endcase
end
@ -105,34 +112,34 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
.vpos(vpos)
);
wire [3:0] car_sprite_yofs;
wire [3:0] car_sprite_addr;
wire [7:0] car_sprite_bits;
car_bitmap car(
.yofs(car_sprite_yofs),
.yofs(car_sprite_addr),
.bits(car_sprite_bits));
wire vstart = {1'd0,player_y} == vpos;
wire hstart = {1'd0,player_x} == hpos;
wire car_gfx;
wire unused;
wire in_progress;
sprite_renderer renderer(
.clk(clk),
.vstart(vstart),
.load(hsync),
.hstart(hstart),
.rom_addr(car_sprite_yofs),
.rom_addr(car_sprite_addr),
.rom_bits(car_sprite_bits),
.gfx(car_gfx),
.in_progress(unused));
always @(posedge hsync)
begin
if (!hpaddle) paddle_x <= vpos[7:0];
if (!vpaddle) paddle_y <= vpos[7:0];
end
.in_progress(in_progress));
always @(posedge hpaddle)
paddle_x <= vpos[7:0];
always @(posedge vpaddle)
paddle_y <= vpos[7:0];
always @(posedge vsync)
begin
player_x <= paddle_x;
@ -141,7 +148,7 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
wire r = 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};
endmodule

View File

@ -8,7 +8,7 @@ module tank_bitmap(addr, bits);
input [7:0] addr;
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];
@ -109,7 +109,9 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits,
output [4:0] rom_addr;
input [7:0] rom_bits;
output gfx;
output busy = state != WAIT_FOR_VSTART;
output busy;
assign busy = state != WAIT_FOR_VSTART;
reg [2:0] state;
reg [3:0] ycount;
@ -178,6 +180,7 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits,
endmodule
module rotation_selector(rotation, bitmap_num, hmirror, vmirror);
input [3:0] rotation;
output [2:0] bitmap_num;
output hmirror, vmirror;
@ -208,23 +211,6 @@ module rotation_selector(rotation, bitmap_num, hmirror, vmirror);
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,
sprite_addr, sprite_bits, gfx,
playfield,
@ -305,9 +291,33 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
end
end
reg collision_detected;
always @(posedge collision_gfx or posedge vsync or posedge reset)
collision_detected <= collision_gfx;
// set if collision; cleared at vsync
reg collision_detected;
always @(posedge clk)
if (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)
if (reset) begin

View File

@ -180,13 +180,13 @@ var VerilogPlatform = function(mainElement, options) {
var self = this;
var video, audio;
var useAudio = false;
var videoWidth = 256+16;
var videoHeight = 240+16;
var maxVideoBlankLines = 80;
var videoWidth = 256+20;
var videoHeight = 240+20;
var maxVideoBlankLines = 40; // vertical hold
var idata, timer;
var gen;
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 paddle_x = 0;
var paddle_y = 0;
@ -235,6 +235,7 @@ var VerilogPlatform = function(mainElement, options) {
if (inspect_obj && inspect_sym) {
var COLOR_BIT_OFF = 0xffff3333;
var COLOR_BIT_ON = 0xffffffff;
/*
for (var y=0; y<videoHeight; y++) {
var val = inspect_data[y * videoWidth];
var i = y * videoWidth + 16;
@ -244,6 +245,14 @@ var VerilogPlatform = function(mainElement, options) {
val >>= 1;
} 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);
idata = video.getFrameData();
// TODO: 15.7 kHz?
timer = new AnimationTimer(frameRate, function() {
if (!self.isRunning())
return;

View File

@ -534,7 +534,7 @@ function setCompileOutput(data) {
editor.setGutterMarker(info.line-1, "gutter-offset", textel);
}
if (info.insns) {
var insnstr = info.insns.length > 8 ? ("...") : info.insns;
var insnstr = info.insns.length > 9 ? ("...") : info.insns;
var textel = document.createTextNode(insnstr);
editor.setGutterMarker(info.line-1, "gutter-bytes", textel);
if (info.iscode) {

View File

@ -70,16 +70,18 @@ var Assembler = function(spec) {
}
function preprocessRules() {
if (spec.width)
width = spec.width|0;
for (var i=0; i<spec.rules.length; i++)
rule2regex(spec.rules[i], spec.vars);
}
if (spec) preprocessRules();
function warning(msg) {
errors.push({msg:msg, line:linenum});
function warning(msg, line) {
errors.push({msg:msg, line:line?line:linenum});
}
function fatal(msg) {
warning(msg);
function fatal(msg, line) {
warning(msg, line);
aborted = true;
}
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)
return s;
else if (s.startsWith("$"))
@ -128,8 +131,7 @@ var Assembler = function(spec) {
var id = m[b+1];
var v = spec.vars[rule.varlist[b]];
if (!v) {
warning("Could not find matching identifier for '" + m[0] + "'");
return;
return {error:"Could not find matching identifier for '" + m[0] + "'"};
}
n = v.bits;
if (v.toks) {
@ -137,7 +139,7 @@ var Assembler = function(spec) {
if (x < 0)
return null;
} else {
x = parseConst(id);
x = parseConst(id, n);
// is it a label? add fixup
if (isNaN(x)) {
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;
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;
oplen += n;
}
@ -206,18 +208,21 @@ var Assembler = function(spec) {
return; // empty line
// look at each rule in order
if (!spec) { fatal("Need to load .spec first"); return; }
var lastError;
for (var i=0; i<spec.rules.length; i++) {
var rule = spec.rules[i];
var m = rule.re.exec(line);
if (m) {
var result = self.buildInstruction(rule, m);
if (result) {
if (result && result.nbits) {
addBytes(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() {
@ -226,15 +231,18 @@ var Assembler = function(spec) {
var fix = fixups[i];
var sym = symbols[fix.sym];
if (sym) {
var ofs = fix.ofs + (fix.bitofs>>3);
var shift = fix.bitofs&7;
var ofs = fix.ofs + Math.floor(fix.bitofs/width);
var shift = fix.bitofs & (width-1);
var mask = ((1<<fix.bitlen)-1);
var value = parseConst(sym.value);
if (fix.iprel) value -= fix.ofs + fix.ipofs;
var value = parseConst(sym.value, fix.bitlen);
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;
// TODO: check range
// TODO: span multiple words?
outwords[ofs - origin] ^= value;
outwords[ofs - origin] ^= value; // TODO: << shift?
} else {
warning("Symbol '" + fix.sym + "' not found");
}

View File

@ -23,12 +23,12 @@ describe('Assemble', function() {
.define F_VSYNC 16
Start:
zero A
zero A ; comment
sta VPU_LO
sta VPU_HI
sta 0
DisplayLoop:
zero B
DisplayLoop:zero B
mov A,[b]
sta VPU_WRITE
sta VPU_MOVE