[myhdl-list] address decoder in myHDL
Brought to you by:
jandecaluwe
From: Aaron F. <aar...@gm...> - 2012-12-02 01:00:52
|
I'm trying to implement a conceptually simple, but Verilog/VHDL-unfriendly module in myHDL. So far I've had success with some simplified forms of the module, but not with the full-fledged spec. The module, an address decoder, takes as input an n-bit address input signal and outputs an m-bit decoded value which can be considered as the binary encoding of a selected slave, according to which of several address ranges the address falls in. If no address range matches, a default value is output. The set of decoded address ranges and their output encodings are parameters of the generator. Here's what one generator instance could look like: module decoder(input [7:0] addr, output [3:0] select); always @(addr) begin if (8'h0 <= addr && addr < 8'h10) select = 4'h0; else if (8'h20 < addr && addr < 8'h23) select = 4'h8; else if ... ... more ranges ... else select = 4'hF; // default value end endmodule Using myHDL, I have been able to create some simplified forms of the decoder Here's one example: module decoder0 ( addr, select ); input [7:0] addr; output [3:0] select; reg [3:0] select; always @(addr) begin: DECODER0_ASSIGNMENTS if (((0 <= addr) && (addr < 16))) begin select = 1; end if (((32 <= addr) && (addr < 64))) begin select = 2; end else begin select = 3; end end endmodule This is easy to implement in myHDL, but the number of decoded ranges is a constant property. In other words, the myHDL python code closely matches the generated Verilog's if/else if /else structure: @always_comb def assignments(): if 0 <= addr and addr < 0x10: select.next = 1 if 0x20 <= addr and addr < 0x40: select.next = 2 else: select.next = 3 An alternate implementation generates this Verilog: module decoder1 ( addr, select ); input [7:0] addr; output [3:0] select; reg [3:0] select; always @(addr[9-1:6]) begin: DECODER1_ASSIGNMENTS case (addr[9-1:6]) 0: select = 3; 1: select = 5; 2: select = 7; 3: select = 9; 4: select = 10; 5: select = 11; 6: select = 14; default: select = 15; endcase end endmodule The myHDL code which created this implementation allows a variable number of decoded ranges, but each range must be the same size. In Python I use the range size and number of ranges to compute the slice indices of the input address signal to shadow for the case select. def decoder1( addr, select, ): # Continue to assume equal-span select ranges which span the entire address space, but now compute the indices # of the shadow signal address_ranges = [(0, 0x40), (0x40, 0x80), (0x80, 0xC0), (0xC0, 0x100), (0x100, 0x140), (0x140, 0x180), (0x180, 0x1C0), (0x1C0, 0x200)], selects = tuple([3, 5, 7, 9, 10, 11, 14, 15]), span = address_ranges[0][1] - address_ranges[0][0] max_address = max(map(lambda span: span[1], address_ranges)) msb = int(math.log(max_address, 2)) lsb = int(math.log(span, 2)) addr_bits = addr(msb, lsb) @always_comb def assignments(): select.next = selects[addr_bits] return assignments For this example, I let the ranges span the entire address space, but if I wanted to decode certain "unallocated" regions to some default value, I could do that easily. I'd like to build a decoder with any number of ranges, whose size may not all be the same. I imagine that the generated HDL should look like an if/else if/.../else structure with a variable number of "else ifs", but there may be another form that I haven't thought of. However, I haven't been able to come up with a solution that combines myHDL's case statement capability (variable number of cases) with range-detect expressions (as in decoder0). Does anyone have any hints? thanks! -Aaron |