diff --git a/assembler/README.md b/assembler/README.md index b9175ab..40b22e9 100644 --- a/assembler/README.md +++ b/assembler/README.md @@ -4,15 +4,19 @@ Example syntax: ``` # text -label: - LOAD a - ADD b - STORE c - JUMP label +loop: + LDV + SUB a + STVI +delay: + SUB a + JNZ delay + LOAD a + JNZ loop +# video (special label to initialize video data, no spaces allowed) +.video 0x00,0x00,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x07,0x08,0x09,0x0A,0x0B,0x0B,0x0C,0x0D,0x0E,0x0F,0x0F,0x10,0x11,0x12,0x13,0x13,0x14,0x15,0x16,0x17,0x17,0x18,0x19,0x1A,0x1B,0x1B,0x1C,0x1D,0x1E,0x1F,0x1F,0x20,0x21,0x22,0x23,0x23,0x24,0x25,0x26,0x27,0x27,0x28,0x29,0x2A,0x2B,0x2B,0x2C,0x2D,0x2E,0x2F,0x2F,0x30,0x31,0x32,0x33,0x33,0x34,0x35,0x36,0x37,0x37,0x38,0x39,0x3A,0x3B,0x3B,0x3C,0x3D,0x3E,0x3F # data .a 1 -.b 2 -.c 3 ``` Based on the code from https://github.com/dmjio/Assembler.py diff --git a/assembler/assembler.py b/assembler/assembler.py index 468e75a..ffd0b0c 100755 --- a/assembler/assembler.py +++ b/assembler/assembler.py @@ -5,7 +5,7 @@ import sys import time -atable, ltable, dtable = {}, {}, {} #initialize global tables +atable, ltable, dtable, vtable = {}, {}, {}, [] #initialize global tables address_size = 4 jump_size = 7 @@ -33,10 +33,11 @@ def prepare_file(filename): return a def translate(a): + global vtable f = [] code = 0 for i in a: - if not is_l_command(i) and not is_d_command(i): + if not is_l_command(i) and not is_d_command(i): f.append(atable[i]) code += 1 if code > space_table["code"]: @@ -45,8 +46,22 @@ def translate(a): elif code < space_table["code"]: for i in range(space_table["code"] - code): f.append(to_b(0, 8)) + video = len(vtable) + if video > space_table["video"]: + print "Warning: video data truncated", video + vtable = vtable[0:space_table["video"]] + for i in vtable: + if is_hex(i): + f.append(to_b(try_parse_int(i, 16),8)) + else: + f.append(to_b(try_parse_int(i),8)) + if video < space_table["video"]: + for i in range(space_table["video"] - video): + f.append(to_b(63, 8)) # white fill + print "Video:", len(vtable), "/", space_table["video"] for i in range(space_table["unused"]): f.append(to_b(255, 8)) + print "Unused:", space_table["unused"] data = [to_b(0, 8) for i in xrange(space_table["data"])] for i in dtable: data[try_parse_int(dtable[i][0], base=2)] = dtable[i][1] @@ -62,8 +77,10 @@ def make_ltable(a): if is_l_command(i): #find a label, add line number to it x -= 1 ltable[i[0:-1]] = to_b(x, jump_size) #use binary helper with 0's padding + print "Label:", i[0:-1], "address", x def make_dtable(a): + global vtable space = 0 for i in a: # add to symbols table if is_d_command(i): @@ -76,9 +93,13 @@ def make_dtable(a): if var in dtable.keys(): print "Error: redefinition of variable '" + var + "'!" sys.exit(7) + elif var == "video": + print "Video data declaration" + vtable = val.split(",") elif try_parse_int(val) is not None: dtable[var] = [to_b(space, address_size), to_b(int(val))] space += 1 + print "Data declaration", var else: dtable[var] = [to_b(space, address_size), to_b(0)] # unable to parse space += 1 @@ -91,7 +112,11 @@ def make_atable(a): for i in a: if not is_d_command(i) and not is_l_command(i): mnemo = i.split(' ')[0] - param = i.split(' ')[1] + if mnemo != 'LDV' and mnemo != 'STVI': + param = i.split(' ')[1] + else: + atable[i] = inst_table[mnemo] + "1111" + continue if mnemo in inst_table.keys(): if mnemo[0] == 'J': if param in ltable: @@ -123,5 +148,3 @@ def write_file(a): main() print "Time: ", time.time()-t0, "s" - - diff --git a/assembler/helpers.py b/assembler/helpers.py index 47988a2..ff09cb1 100644 --- a/assembler/helpers.py +++ b/assembler/helpers.py @@ -5,6 +5,7 @@ is_l_command = lambda i : i.find(':') != -1 # labels ends with ':' is_a_command = lambda i : i.find(' ') == 0 or i.find('\t') == 0 # assembly commands must be indented (further removed) is_d_command = lambda i : i.find('.') == 0 # data variables starts with '.' +is_hex = lambda i : i.find('0x') == 0 # Hexadecimal #attempts to parse an integer def try_parse_int(s, base=10, val=None): diff --git a/assembler/tables.py b/assembler/tables.py index f7347c6..53028f6 100644 --- a/assembler/tables.py +++ b/assembler/tables.py @@ -1,13 +1,16 @@ inst_table = { + "LDV" : "0000", + "STVI" : "0001", "ADD" : "0101", "SUB" : "0110", "LOAD" : "0100", "STORE" : "0011", - "JUMP" : "1" + "JNZ" : "1" } space_table = { "code" : 128, - "unused" : 112, + "video" : 80, + "unused" : 32, "data" : 16 } diff --git a/assembler/vga.asm b/assembler/vga.asm new file mode 100644 index 0000000..a7f384d --- /dev/null +++ b/assembler/vga.asm @@ -0,0 +1,12 @@ +loop: + LDV + SUB a + STVI +delay: + SUB a + JNZ delay + LOAD a + JNZ loop + +.video 0x00,0x00,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x07,0x08,0x09,0x0A,0x0B,0x0B,0x0C,0x0D,0x0E,0x0F,0x0F,0x10,0x11,0x12,0x13,0x13,0x14,0x15,0x16,0x17,0x17,0x18,0x19,0x1A,0x1B,0x1B,0x1C,0x1D,0x1E,0x1F,0x1F,0x20,0x21,0x22,0x23,0x23,0x24,0x25,0x26,0x27,0x27,0x28,0x29,0x2A,0x2B,0x2B,0x2C,0x2D,0x2E,0x2F,0x2F,0x30,0x31,0x32,0x33,0x33,0x34,0x35,0x36,0x37,0x37,0x38,0x39,0x3A,0x3B,0x3B,0x3C,0x3D,0x3E,0x3F +.a 1 diff --git a/processor/clk_wiz_1.sv b/processor/clk_wiz_1.sv new file mode 100644 index 0000000..e296642 --- /dev/null +++ b/processor/clk_wiz_1.sv @@ -0,0 +1,4 @@ +// Substitutes Xilinx IP core for simulation purposes +module clk_wiz_1(output clk_out, input clk_in); + assign clk_out = clk_in; +endmodule diff --git a/processor/cpu.sv b/processor/cpu.sv index e610cc0..8b0cd69 100644 --- a/processor/cpu.sv +++ b/processor/cpu.sv @@ -1,4 +1,4 @@ -module uP( +module cpu( input clock, reset, inout [7:0] mbr, output logic we, @@ -7,12 +7,13 @@ module uP( typedef enum logic [1:0] {FETCH, DECODE, EXECUTE} statetype; statetype state, nextstate; - logic [7:0] acc; + logic [7:0] acc, vaddr; always @(posedge clock or posedge reset) begin if (reset) begin - pc = 'b0; + pc <= 'b0; + vaddr <= 8'b10000000; // 128 state <= FETCH; end else begin @@ -24,17 +25,31 @@ module uP( end DECODE: begin ir = mbr; - mar <= {4'b1111, ir[3:0]}; + if (ir[7:5] == 3'b000) // load/store video + mar <= vaddr; + else + mar <= {4'b1111, ir[3:0]}; end EXECUTE: begin - if (ir[7] == 1'b1) // jump + if (ir[7] == 1'b1 && acc != 8'b00000000) // jnz pc <= {1'b0, ir[6:0]}; else if (ir[7:4] == 4'b0100) // indirect load acc <= mbr; else if (ir[7:4] == 4'b0101) // add acc + data acc <= acc + mbr; + else if (ir[7:4] == 4'b0110) // sub acc - data + acc <= acc - mbr; else if (ir[7:4] == 4'b0011) // store we <= 1'b1; + else if (ir[7:4] == 4'b0000) // load video + acc <= mbr; + else if (ir[7:4] == 4'b0001) // store video + begin + we <= 1'b1; + vaddr <= vaddr + 1; + if (vaddr > 207) + vaddr <= 8'b10000000; // 128 + end end endcase state <= nextstate; @@ -51,4 +66,3 @@ module uP( assign mbr = we ? acc : 'bz; endmodule - diff --git a/processor/mem.sv b/processor/mem.sv index 900feb7..c286259 100644 --- a/processor/mem.sv +++ b/processor/mem.sv @@ -1,15 +1,17 @@ module mem #(parameter filename = "ram.hex") (input clock, we, input [7:0] address, - inout [7:0] data); + inout [7:0] data, + input [7:0] vaddr, + output [7:0] vdata); logic [7:0] RAM[255:0]; initial - // $readmemh(filename, RAM); //Hex file - $readmemb(filename, RAM); //Bin file + $readmemb(filename, RAM); assign data = we ? 'bz : RAM[address]; + assign vdata = RAM[vaddr]; always @(posedge clock) if (we) RAM[address] <= data; diff --git a/processor/por.sv b/processor/por.sv new file mode 100644 index 0000000..d23dda2 --- /dev/null +++ b/processor/por.sv @@ -0,0 +1,18 @@ +module power_on_reset( + input clk, + output reset); + + reg q0 = 1'b0; + reg q1 = 1'b0; + reg q2 = 1'b0; + + always@(posedge clk) + begin + q0 <= 1'b1; + q1 <= q0; + q2 <= q1; + end + + assign reset = !(q0 & q1 & q2); +endmodule + diff --git a/processor/tb.sv b/processor/tb.sv new file mode 100644 index 0000000..8ed89ee --- /dev/null +++ b/processor/tb.sv @@ -0,0 +1,16 @@ +module tb; + reg clock; + + top dut(clock); + + initial + begin + $dumpfile("dump.vcd"); $dumpvars(0); + #50000; $stop; + end + + always + begin + clock <= 1; #5; clock <= 0; #5; + end +endmodule diff --git a/processor/top.sv b/processor/top.sv index 0dd2f31..8fd02be 100644 --- a/processor/top.sv +++ b/processor/top.sv @@ -1,21 +1,17 @@ -module up_tb; - logic clock, reset, we; - logic [7:0] address, ir, pc; - wire [7:0] data; - - uP proc(clock, reset, data, we, address, pc, ir); -// mem #("fibo.hex") ram(clock, we, address, data); - mem #("fibo.bin") ram(clock, we, address, data); - - initial - begin - $dumpfile("dump.vcd"); $dumpvars(0); - reset <= 1; #22; reset <= 0; - #5000; $stop; - end +module top( + input sysclk, // 125MHz + output [3:0] led, + output led5_r, led5_g, led5_b, led6_r, led6_g, led6_b, + output [3:0] VGA_R, VGA_G, VGA_B, + output VGA_HS_O, VGA_VS_O); - always - begin - clock <= 1; #5; clock <= 0; #5; - end + wire pixel_clk, reset, we; + wire [7:0] address, data, vaddr, vdata; + + power_on_reset por(sysclk, reset); + clk_wiz_1 clockdiv(pixel_clk, sysclk); // 25MHz + cpu proc(sysclk, reset, data, we, address); + mem #("vga.bin") ram(sysclk, we, address, data, vaddr, vdata); + vga video(pixel_clk, reset, vdata, vaddr, VGA_R, VGA_G, VGA_B, VGA_HS_O, VGA_VS_O); endmodule + diff --git a/processor/vga.sv b/processor/vga.sv new file mode 100644 index 0000000..9080b8f --- /dev/null +++ b/processor/vga.sv @@ -0,0 +1,52 @@ +module vga( + input clk, reset, + input [7:0] vdata, + output [7:0] vaddr, + output [3:0] VGA_R, VGA_G, VGA_B, + output VGA_HS_O, VGA_VS_O); + + reg [9:0] CounterX, CounterY; + reg inDisplayArea; + reg vga_HS, vga_VS; + + wire CounterXmaxed = (CounterX == 800); // 16 + 48 + 96 + 640 + wire CounterYmaxed = (CounterY == 525); // 10 + 2 + 33 + 480 + wire [3:0] row, col; + + always @(posedge clk or posedge reset) + if (reset) + CounterX <= 0; + else + if (CounterXmaxed) + CounterX <= 0; + else + CounterX <= CounterX + 1; + + always @(posedge clk or posedge reset) + if (reset) + CounterY <= 0; + else + if (CounterXmaxed) + if(CounterYmaxed) + CounterY <= 0; + else + CounterY <= CounterY + 1; + + assign row = (CounterY>>6); + assign col = (CounterX>>6); + assign vaddr = {1'b1,col[3:0],row[2:0]}; + + always @(posedge clk) + begin + vga_HS <= (CounterX > (640 + 16) && (CounterX < (640 + 16 + 96))); // active for 96 clocks + vga_VS <= (CounterY > (480 + 10) && (CounterY < (480 + 10 + 2))); // active for 2 clocks + inDisplayArea <= (CounterX < 640) && (CounterY < 480); + end + + assign VGA_HS_O = ~vga_HS; + assign VGA_VS_O = ~vga_VS; + + assign VGA_R = inDisplayArea ? {vdata[5:4], 2'b00} : 4'b0000; + assign VGA_G = inDisplayArea ? {vdata[3:2], 2'b00} : 4'b0000; + assign VGA_B = inDisplayArea ? {vdata[1:0], 2'b00} : 4'b0000; +endmodule