From 60e1775b874015a3451e4bde10a8eb30701b1165 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Tue, 6 Jul 2021 09:44:36 -0700 Subject: Initial commit. --- .gitignore | 1 + Makefile | 7 ++ asm.rb | 196 +++++++++++++++++++++++++++++++++++ boards/decode/decode.kicad_pcb | 1 + boards/decode/decode.pro | 33 ++++++ boards/decode/decode.sch | 4 + fib.s | 21 ++++ insts.rb | 228 +++++++++++++++++++++++++++++++++++++++++ modules.rb | 32 ++++++ sim/.gitignore | 2 + sim/Makefile | 12 +++ sim/alu.sv | 76 ++++++++++++++ sim/control.sv | 54 ++++++++++ sim/decode.sv | 82 +++++++++++++++ sim/main.cpp | 61 +++++++++++ sim/memory.sv | 35 +++++++ sim/pc.sv | 36 +++++++ sim/rf.sv | 39 +++++++ sim/tmp.sv | 41 ++++++++ sim/top.sv | 27 +++++ sim/uart.sv | 47 +++++++++ sim/urom.sv | 19 ++++ uasm.rb | 174 +++++++++++++++++++++++++++++++ vectors.rb | 7 ++ 24 files changed, 1235 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 asm.rb create mode 100644 boards/decode/decode.kicad_pcb create mode 100644 boards/decode/decode.pro create mode 100644 boards/decode/decode.sch create mode 100644 fib.s create mode 100644 insts.rb create mode 100644 modules.rb create mode 100644 sim/.gitignore create mode 100644 sim/Makefile create mode 100644 sim/alu.sv create mode 100644 sim/control.sv create mode 100644 sim/decode.sv create mode 100644 sim/main.cpp create mode 100644 sim/memory.sv create mode 100644 sim/pc.sv create mode 100644 sim/rf.sv create mode 100644 sim/tmp.sv create mode 100644 sim/top.sv create mode 100644 sim/uart.sv create mode 100644 sim/urom.sv create mode 100755 uasm.rb create mode 100644 vectors.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2e7327 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/out diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..31000b8 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +run: out/image.hex + $(MAKE) -C sim +.PHONY: run + +out/image.hex: fib.s $(wildcard *.rb) + ./uasm.rb + ./asm.rb $< | expand -t 24 > $@ diff --git a/asm.rb b/asm.rb new file mode 100755 index 0000000..2ca9155 --- /dev/null +++ b/asm.rb @@ -0,0 +1,196 @@ +#!/usr/bin/ruby -w + +$insts = {} + +$next_opcode = 0 + +def inst(pattern, vector=false, &code) + return if vector + throw "instruction with this pattern already defined" if $insts.member?(pattern) + $insts[pattern] = $next_opcode + $next_opcode += 1 +end + +load "insts.rb" + +$labels = {} +$pc = 0 + +ARGF.each_line do | line | + line.chomp! + line.gsub!(/^\s+/, "") + line.gsub!(/#.*/, "") + line.gsub!(/\s+$/, "") + + next if line == "" + + if line =~ /^([a-zA-Z_][a-zA-Z0-9_]*):$/ + $labels[$1] = $pc + $stdout.write("\t// #{line}\n") + next + elsif line =~ /^\.origin\s+((?:0x[0-9a-fA-F]+)?(?:\d+))$/ + $pc = $1.to_i(0) + $stdout.write("@#{$pc.to_s(16)}\t// #{line}\n") + next + elsif line =~ /^\.bytes?\s+(.*)$/ + data = $1.split(/\s+/) + data.map { | x | throw "invalid byte #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ } + data = data.map { | x | x.to_i(0) } + data = data.map { | x | x < 0 ? x + 0x100 : x } + data.map { | x | throw "invalid byte 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xff } + data = data.map { | x | x.to_s(16).rjust(2, "0") } + $pc += data.size + $stdout.write("#{data.join(" ")}\t// #{line}\n") + next + elsif line =~ /^\.shorts?\s+(.*)$/ + data = $1.split(/\s+/) + data.map { | x | throw "invalid short #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ } + data = data.map { | x | x.to_i(0) } + data = data.map { | x | x < 0 ? x + 0x10000 : x } + data.map { | x | throw "invalid short 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xffff } + data = data.flat_map { | x | [x & 0xff, x >> 8] } + data = data.map { | x | x.to_s(16).rjust(2, "0") } + $pc += data.size + $stdout.write("#{data.join(" ")}\t// #{line}\n") + next + elsif line =~ /^\.longs?\s+(.*)$/ + data = $1.split(/\s+/) + data.map { | x | throw "invalid long #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ } + data = data.map { | x | x.to_i(0) } + data = data.map { | x | x < 0 ? x + 0x100000000 : x } + data.map { | x | throw "invalid long 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xffffffff } + data = data.flat_map { | x | [x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, x >> 24] } + data = data.map { | x | x.to_s(16).rjust(2, "0") } + $pc += data.size + $stdout.write("#{data.join(" ")}\t// #{line}\n") + next + elsif line =~ /^\.quads?\s+(.*)$/ + data = $1.split(/\s+/) + data.map { | x | throw "invalid quad #{x}" unless x =~ /^-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+))$/ } + data = data.map { | x | x.to_i(0) } + data = data.map { | x | x < 0 ? x + 0x10000000000000000 : x } + data.map { | x | throw "invalid quad 0x#{x.to_s(16)}" unless x >= 0 && x <= 0xffffffffffffffff } + data = data.flat_map { | x | [x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff, (x >> 32) & 0xff, (x >> 40) & 0xff, (x >> 48) & 0xff, x >> 56] } + data = data.map { | x | x.to_s(16).rjust(2, "0") } + $pc += data.size + $stdout.write("#{data.join(" ")}\t// #{line}\n") + next + end + + parts = line.split(/\s+/) + + patterns = [parts.shift] + values = [] + parts.each do | part | + case part + when /^(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))$/ + patterns << "#" + values << $1.to_i(0) + when /^([a-zA-Z_][a-zA-Z0-9_]+)$/ + throw "unknown label #{$1}" unless $labels.member?($1) + patterns << "#" + values << $labels[$1] + when /^\$(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))$/ + patterns << "$" + values << $1.to_i(0) + when /^\[(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))\]$/ + patterns << "[#]" + values << $1.to_i(0) + when /^\[([a-zA-Z_][a-zA-Z0-9_]+)\]$/ + throw "unknown label #{$1}" unless $labels.member?($1) + patterns << "[#]" + values << $labels[$1] + when /^\[\$(-?(?:(?:0x[0-9a-fA-F]+)|(?:\d+)))\]$/ + patterns << "[$]" + values << $1.to_i(0) + else + throw "invalid part #{part}" + end + end + + pattern = patterns.join(" ") + throw "unknown instruction pattern #{pattern}" unless $insts.member?(pattern) + opcode = $insts[pattern] + + # Encoding format: + # +-+-+-+-+-+-+-+-+ + # |M|I|SEL| SHIFT | + # +-+-+-+-+-+-+-+-+ + # M = More data after this + # I = Invert this field before shifting + # SEL = Field selector (0=opcode, 2=A, 3=B) + # SHIFT = Data to shift in + + # This gives us these common first nibbles: + # 0 last opcode byte + # 8 extended opcode byte + # A operand A byte + # B operand B byte + # E operand A byte (with inversion) + # F operand B byte (with inversion) + + space = false + values.each_with_index do | value, idx | + inverted = value < 0 + if inverted + value *= -1 + value -= 1 + end + nibbles = [] + while value != 0 + nibbles << (value & 0xf).to_s(16) + value = value >> 4 + end + if inverted and nibbles.empty? + nibbles << "f" + end + nibbles.reverse! + if idx == 0 + if inverted + $stdout.write(" ") if space + $stdout.write("e#{nibbles.shift}") + $pc += 1 + space = true + end + nibbles.each do | nibble | + $stdout.write(" ") if space + $stdout.write("a#{nibble}") + $pc += 1 + space = true + end + elsif idx == 1 + if inverted + $stdout.write(" ") if space + $stdout.write("f#{nibbles.shift}") + $pc += 1 + space = true + end + nibbles.each do | nibble | + $stdout.write(" ") if space + $stdout.write("b#{nibble}") + $pc += 1 + space = true + end + else + throw "don't know how to encode this many fields" + end + end + + nibbles = [] + while opcode != 0 + nibbles << (opcode & 0xf).to_s(16) + opcode = opcode >> 4 + end + nibbles << "0" if nibbles.empty? + last = nibbles.shift + nibbles.reverse! + nibbles.each do | nibble | + $stdout.write(" ") if space + $stdout.write("8#{nibble}") + $pc += 1 + space = true + end + $stdout.write(" ") if space + $stdout.write("0#{last}\t// #{line}\n") + $pc += 1 +end diff --git a/boards/decode/decode.kicad_pcb b/boards/decode/decode.kicad_pcb new file mode 100644 index 0000000..02c8ecb --- /dev/null +++ b/boards/decode/decode.kicad_pcb @@ -0,0 +1 @@ +(kicad_pcb (version 4) (host kicad "dummy file") ) diff --git a/boards/decode/decode.pro b/boards/decode/decode.pro new file mode 100644 index 0000000..152769c --- /dev/null +++ b/boards/decode/decode.pro @@ -0,0 +1,33 @@ +update=22/05/2015 07:44:53 +version=1 +last_client=kicad +[general] +version=1 +RootSch= +BoardNm= +[pcbnew] +version=1 +LastNetListRead= +UseCmpFile=1 +PadDrill=0.600000000000 +PadDrillOvalY=0.600000000000 +PadSizeH=1.500000000000 +PadSizeV=1.500000000000 +PcbTextSizeV=1.500000000000 +PcbTextSizeH=1.500000000000 +PcbTextThickness=0.300000000000 +ModuleTextSizeV=1.000000000000 +ModuleTextSizeH=1.000000000000 +ModuleTextSizeThickness=0.150000000000 +SolderMaskClearance=0.000000000000 +SolderMaskMinWidth=0.000000000000 +DrawSegmentWidth=0.200000000000 +BoardOutlineThickness=0.100000000000 +ModuleOutlineThickness=0.150000000000 +[cvpcb] +version=1 +NetIExt=net +[eeschema] +version=1 +LibDir= +[eeschema/libraries] diff --git a/boards/decode/decode.sch b/boards/decode/decode.sch new file mode 100644 index 0000000..fff8c68 --- /dev/null +++ b/boards/decode/decode.sch @@ -0,0 +1,4 @@ +EESchema Schematic File Version 2 +EELAYER 25 0 +EELAYER END +$EndSCHEMATC diff --git a/fib.s b/fib.s new file mode 100644 index 0000000..c2e70bf --- /dev/null +++ b/fib.s @@ -0,0 +1,21 @@ +mov $0 0 +mov $1 1 +mov $2 0x8000 + +loop: + +mov [$2] $0 +add $2 1 + +tx $0 + +mov $-1 $0 +add $-1 $1 +mov $0 $1 +mov $1 $-1 + +mov $-1 $2 +eq $-1 0x800a +jz $-1 loop + +hlt diff --git a/insts.rb b/insts.rb new file mode 100644 index 0000000..bc9c156 --- /dev/null +++ b/insts.rb @@ -0,0 +1,228 @@ +inst "hlt" do + @control.halt +end + +inst "mov $ #" do + uop { @decode.outaddr_a; @decode.outdata_b; @rf.store } +end + +inst "mov $ $" do + uop { @decode.outaddr_b; @rf.outdata; @tmp0.loaddata } + uop { @decode.outaddr_a; @tmp0.outdata; @rf.store } +end + +inst "mov [#] #" do + uop { @decode.outaddr_a; @decode.outdata_b; @memory.store } +end + +inst "mov [#] $" do + uop { @decode.outaddr_b; @rf.outdata; @tmp0.loaddata } + uop { @decode.outaddr_a; @tmp0.outdata; @memory.store } +end + +inst "mov [$] #" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @decode.outdata_b; @tmp0.outaddr; @memory.store } +end + +inst "mov [$] $" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @decode.outaddr_b; @rf.outdata; @tmp1.loaddata } + uop { @tmp0.outaddr; @tmp1.outdata; @memory.store } +end + +inst "mov $ [#]" do + uop { @decode.outaddr_b; @memory.outdata; @tmp0.loaddata } + uop { @decode.outaddr_a; @tmp0.outdata; @rf.store } +end + +inst "mov $ [$]" do + uop { @decode.outaddr_b; @rf.outdata; @tmp0.loaddata } + uop { @tmp0.outaddr; @memory.outdata; @tmp1.loaddata } + uop { @decode.outaddr_a; @tmp1.outdata; @rf.store } +end + +inst "skipz $" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @tmp0.outdata; @control.set_uip_if_nonzero; constaddr($eom) } + uop { @decode.clear } + decode_loop = uip() + uop { @pc.increment; @pc.outaddr; @memory.outdata; @decode.decode } + uop { @decode.outdata_needmore; @control.set_uip_if_nonzero; constaddr(decode_loop) } +end + +inst "skipnz $" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @tmp0.outdata; @control.set_uip_if_nonzero; constaddr(uip()+2) } + uop { @control.set_uip; constaddr($eom) } + uop { @decode.clear } + decode_loop = uip() + uop { @pc.increment; @pc.outaddr; @memory.outdata; @decode.decode } + uop { @decode.outdata_needmore; @control.set_uip_if_nonzero; constaddr(decode_loop) } +end + +inst "push $ #" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @tmp0.outaddr; @alu.sub; constdata(1) } + uop { @decode.outaddr_a; @alu.outdata; @rf.store } + uop { @decode.outdata_b; @alu.outaddr; @memory.store } +end + +inst "push $ $" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @tmp0.outaddr; @alu.sub; constdata(1) } + uop { @decode.outaddr_a; @alu.outdata; @rf.store } + uop { @decode.outaddr_b; @rf.outdata; @tmp1.loaddata } + uop { @tmp1.outdata; @alu.outaddr; @memory.store } +end + +inst "pop $ $" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @tmp0.outaddr; @alu.add; constdata(1) } + uop { @decode.outaddr_a; @alu.outdata; @rf.store } + uop { @alu.outaddr; @memory.outdata; @tmp0.loaddata } + uop { @decode.outaddr_b; @tmp0.outdata; @rf.store } +end + +def alu(op) + inst "#{op} $ #" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @decode.outdata_b; @tmp0.outaddr; @alu.send(op) } + uop { @decode.outaddr_a; @alu.outdata; @rf.store } + end + + inst "#{op} $ $" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @decode.outaddr_b; @rf.outdata; @tmp1.loaddata } + uop { @tmp0.outaddr; @tmp1.outdata; @alu.send(op) } + uop { @decode.outaddr_a; @alu.outdata; @rf.store } + end +end + +alu :and +alu :or +alu :xor +alu :add +alu :sub +alu :cmp +alu :lshift +alu :rshift + +def cmpbit(name, bit) + inst "#{name} $ #" do + uop { @decode.outaddr_a; @rf.outdata; @tmp0.loaddata } + uop { @decode.outdata_b; @tmp0.outaddr; @alu.cmp } + uop { @alu.outdata; @alu.and; constaddr(1< dbus, + abus == dbus, + abus < dbus}; +assign lshift_result = (dbus >= BUS_BITS) ? 0 : (abus << dbus); +assign rshift_result = (dbus >= BUS_BITS) ? 0 : (abus >> dbus); + +bit [BUS_BITS-1:0] newx; +assign newx = + (sel == 0) ? and_result : + (sel == 1) ? or_result : + (sel == 2) ? xor_result : + (sel == 3) ? add_result : + (sel == 4) ? sub_result : + (sel == 5) ? cmp_result : + (sel == 6) ? lshift_result : + (sel == 7) ? rshift_result : + {(BUS_BITS){1'bX}}; + +assign abus = ctrl[OUTADDR] ? x : {(BUS_BITS){1'bZ}}; +assign dbus = ctrl[OUTDATA] ? x : {(BUS_BITS){1'bZ}}; + +always @(posedge clk) begin + if (ctrl[OP]) begin + x <= newx; + end +end + +endmodule diff --git a/sim/control.sv b/sim/control.sv new file mode 100644 index 0000000..7808f61 --- /dev/null +++ b/sim/control.sv @@ -0,0 +1,54 @@ +module control + #( parameter UROM = "" + , parameter UIP_BITS = 15 + , parameter UROM_BITS = 8 + , parameter BUS_BITS = 16 + , parameter CONST_0 = "" + , parameter CONST_1 = "" + , parameter RESET = ~0 + ) + ( input bit clk + , input bit reset + , output bit [UIP_BITS-1:0] uip + , inout bit [BUS_BITS-1:0] abus + , inout bit [BUS_BITS-1:0] dbus + ); + +typedef enum + { HALT + , SET_UIP_COND + , NOCOND + , OUTADDR + , OUTDATA + } CtrlBit; + +bit [UROM_BITS-1:0] ctrl; +urom#(UROM, UIP_BITS, UROM_BITS) urom(uip, ctrl); + +bit [UROM_BITS*2-1:0] constant; +urom#(CONST_0, UIP_BITS, UROM_BITS) const_0(uip, constant[1*UROM_BITS-1:0*UROM_BITS]); +urom#(CONST_1, UIP_BITS, UROM_BITS) const_1(uip, constant[2*UROM_BITS-1:1*UROM_BITS]); + +assign abus = ctrl[OUTADDR] ? constant : {(BUS_BITS){1'bZ}}; +assign dbus = ctrl[OUTDATA] ? constant : {(BUS_BITS){1'bZ}}; + +bit cond; +assign cond = (dbus != 0) || ctrl[NOCOND]; + +always @(posedge clk) begin + if (reset) begin + uip <= RESET; + end else begin + if (! ctrl[HALT]) begin + if (ctrl[SET_UIP_COND] && cond) begin + uip <= abus[UIP_BITS-1:0]; + end else begin + uip <= uip + 1; + end + end else begin + $finish; + end + end +end + +endmodule diff --git a/sim/decode.sv b/sim/decode.sv new file mode 100644 index 0000000..5c9a9c9 --- /dev/null +++ b/sim/decode.sv @@ -0,0 +1,82 @@ +module decode + #( parameter UROM = "" + , parameter UIP_BITS = 15 + , parameter UROM_BITS = 8 + , parameter BUS_BITS = 16 + , parameter OPCODE_BITS = 8 + ) + ( input bit clk + , input bit reset + , input bit [UIP_BITS-1:0] uip + , inout bit [BUS_BITS-1:0] abus + , inout bit [BUS_BITS-1:0] dbus + ); + +bit [OPCODE_BITS-1:0] opcode; +bit [BUS_BITS-1:0] a; +bit [BUS_BITS-1:0] b; +bit needmore; + +bit [UIP_BITS-1:0] new_uip; +assign new_uip = {opcode, {(UIP_BITS-OPCODE_BITS){1'b0}}}; + +typedef enum + { CLEAR + , DECODE + , OUTADDR + , OUTADDR_SEL0 + , OUTADDR_SEL1 + , OUTDATA + , OUTDATA_SEL0 + , OUTDATA_SEL1 + } CtrlBit; + +bit [UROM_BITS-1:0] ctrl; +urom#(UROM, UIP_BITS, UROM_BITS) urom(uip, ctrl); + +bit [1:0] asel; +assign asel = {ctrl[OUTADDR_SEL1], ctrl[OUTADDR_SEL0]}; + +bit [1:0] dsel; +assign dsel = {ctrl[OUTDATA_SEL1], ctrl[OUTDATA_SEL0]}; + +bit [BUS_BITS-1:0] aout; +assign aout = + (asel == 0) ? a : + (asel == 1) ? b : + (asel == 2) ? {{(BUS_BITS-UIP_BITS){1'b0}}, new_uip} : + {(BUS_BITS){1'bX}}; + +assign abus = ctrl[OUTADDR] ? aout : {(BUS_BITS){1'bZ}}; + +bit [BUS_BITS-1:0] dout; +assign dout = + (dsel == 0) ? a : + (dsel == 1) ? b : + (dsel == 2) ? {{(BUS_BITS-1){1'b0}}, needmore} : + {(BUS_BITS){1'bX}}; + +assign dbus = ctrl[OUTDATA] ? dout : {(BUS_BITS){1'bZ}}; + +always @(posedge clk) begin + if (reset || ctrl[CLEAR]) begin + opcode <= 0; + a <= 0; + b <= 0; + needmore <= 1; + end else if (ctrl[DECODE]) begin + automatic bit m = dbus[7]; + automatic bit i = dbus[6]; + automatic bit [1:0] field = dbus[5:4]; + automatic bit [3:0] shift = dbus[3:0]; + needmore <= m; + if (field == 0) begin + opcode <= {i ? ~opcode[OPCODE_BITS-1-4:0] : opcode[OPCODE_BITS-1-4:0], shift}; + end else if (field == 2) begin + a <= {i ? ~a[BUS_BITS-1-4:0] : a[BUS_BITS-1-4:0], shift}; + end else if (field == 3) begin + b <= {i ? ~b[BUS_BITS-1-4:0] : b[BUS_BITS-1-4:0], shift}; + end + end +end +endmodule diff --git a/sim/main.cpp b/sim/main.cpp new file mode 100644 index 0000000..ac4befa --- /dev/null +++ b/sim/main.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +#include "Vtop.h" + +std::uint64_t phases = 0; + +double sc_time_stamp() +{ + return (double)phases / 2; +} + +int main(int argc, const char *argv[]) +{ + Verilated::commandArgs(argc, argv); + + Verilated::traceEverOn(true); + VerilatedVcdC vcd; + + Vtop top; + top.trace(&vcd, 100 /* levels of hierarchy */); + + vcd.set_time_unit("ns"); + vcd.set_time_resolution("ns"); + vcd.open("build/out.vcd"); + + std::cout << "*** RESET SEQUENCE ***\n"; + + top.clk = 0; + top.reset = 1; + top.eval(); + vcd.dump(++phases); + + top.clk = 1; + top.eval(); + vcd.dump(++phases); + + top.clk = 0; + top.reset = 0; + top.eval(); + vcd.dump(++phases); + + std::cout << "*** MAIN LOOP ***\n"; + + for (unsigned int i = 0; i < 10000 && !Verilated::gotFinish(); ++i) { + top.clk = 1; + top.eval(); + vcd.dump(++phases); + top.clk = 0; + top.eval(); + vcd.dump(++phases); + } + + std::cout << "\n"; + + vcd.close(); + + return 0; +} diff --git a/sim/memory.sv b/sim/memory.sv new file mode 100644 index 0000000..0eb1233 --- /dev/null +++ b/sim/memory.sv @@ -0,0 +1,35 @@ +module memory + #( parameter UROM = "" + , parameter UIP_BITS = 15 + , parameter UROM_BITS = 8 + , parameter BUS_BITS = 16 + , parameter IMAGE = "" + , parameter BYTE_BITS = 8 + ) + ( input bit clk + , input bit reset + , input bit [UIP_BITS-1:0] uip + , inout bit [BUS_BITS-1:0] abus + , inout bit [BUS_BITS-1:0] dbus + ); + +bit [BYTE_BITS-1:0] storage [0:(1< 8 + $stdout.write("\t\t#{idx >> 3}.#{idx & 0x7}\t#{bit}\n") + else + $stdout.write("\t\t#{idx}\t#{bit}\n") + end + bitmap[bit] = 1 << idx + proxy.define_singleton_method(bit) do + if $this_uop + $this_uop[name] |= 1 << idx + else + uop do + $this_uop[name] |= 1 << idx + end + end + end + end + proxy.instance_variable_set(:@bitmap, bitmap) + instance_variable_set("@#{name}", proxy) +end + +def urom_alias(urom, name, *bits) + merged = 0 + proxy = instance_variable_get("@#{urom}") + bitmap = proxy.instance_variable_get(:@bitmap) + throw "Name already in use" if bitmap.member?(name) + bits.each do | bit | + merged |= bitmap[bit] + end + bitmap[name] = merged + proxy.define_singleton_method(name) do + if $this_uop + $this_uop[urom] |= merged + else + uop { $this_uop[urom] |= merged } + end + end + proxy.instance_variable_set(:@bitmap, bitmap) +end + +def inst(pattern, vector=false, &code) + throw "nested instruction" if $this_inst + throw "instruction with this pattern already defined" if $insts.member?(pattern) + throw "too many opcodes" if $next_opcode > $next_vector + $this_opnum = vector ? $next_vector : $next_opcode + $stdout.write("\t#{$this_opnum.to_s(16)}\t#{($this_opnum << UIP_BITS_PER_OPCODE).to_s(16)}\t#{pattern}\n") + $this_inst = [] + code.call + if not vector + $eom ||= uip() + uop { @decode.clear; @control.set_uip; constaddr($insts["!bom"] << UIP_BITS_PER_OPCODE) } + end + $this_inst.each_with_index do | uop, idx | + uip = ($this_opnum << UIP_BITS_PER_OPCODE) + idx + uop.each do | urom, entry | + $uroms[urom][uip] = entry + end + end + $insts[pattern] = $this_opnum + $this_opnum = nil + $this_inst = nil + if vector + $next_vector -= 1 + else + $next_opcode += 1 + end +end + +def vector(name, &code) + inst("!#{name}", true, &code) +end + +def uop(&code) + throw "not in instruction" unless $this_inst + throw "nested uop" if $this_uop + throw "too many uops" if $this_inst.size >= (1 << UIP_BITS_PER_OPCODE) + $this_uop = {} + $uroms.each_key do | urom | + $this_uop[urom] = 0 + end + code.call + $this_inst << $this_uop + $this_uop = nil +end + +def const(value) + throw "Value out of range" if value < 0 or value > 0xffff + if $this_uop + $this_uop[:consts] = value + else + uop do + $this_uop[:consts] = value + end + end +end + +def constaddr(value) + const(value) + @control.outaddr +end + +def constdata(value) + const(value) + @control.outdata +end + +def uip() + throw "not in instruction" unless $this_inst + return ($this_opnum << UIP_BITS_PER_OPCODE) + $this_inst.size +end + +$stdout.write("Control wires:\n") +load "modules.rb" + +$stdout.write("\nOpcodes:\n") +load "vectors.rb" +load "insts.rb" + +$stdout.write("\nWriting µrom contents:\n") +$uroms.each do | urom, data | + $stdout.write("\t#{urom}...") + $stdout.flush + if $urom_sizes[urom] > 8 + 0.upto(($urom_sizes[urom] / 8.0).ceil - 1) do | bank | + $stdout.write(" #{bank}") + $stdout.flush + File.open("out/#{urom}.#{bank}.bin", "wb") do | fh | + data.each do | word | + fh.write(((word >> (8 * bank)) & 0xff).chr) + end + end + end + else + File.open("out/#{urom}.bin", "wb") do | fh | + data.each do | byte | + fh.write(byte.chr) + end + end + end + $stdout.write("\n") +end diff --git a/vectors.rb b/vectors.rb new file mode 100644 index 0000000..62b58d5 --- /dev/null +++ b/vectors.rb @@ -0,0 +1,7 @@ +vector :bom do + $start_of_bom = uip() + decode_loop = uip() + uop { @pc.increment; @pc.outaddr; @memory.outdata; @decode.decode } + uop { @decode.outdata_needmore; @control.set_uip_if_nonzero; constaddr(decode_loop) } + uop { @decode.outaddr_uip; @control.set_uip } +end -- cgit v1.2.3