§ В чем интерес

Сегодня я попробую сконвертировать код Verilog на JS и проверить, что из этого получится.

§ Исходный код на верилоге

1module vga
2(
3    input               clock,
4    output      [1:0]   r,
5    output      [1:0]   g,
6    output      [1:0]   b,
7    output              hs,
8    output              vs,
9    output reg  [12:0]  address,
10    input       [ 7:0]  data,
11    input       [10:0]  cursor
12);
13
14reg [9:0]   x = 10'b0;
15reg [8:0]   y = 9'b0;
16
17// Мерцания
18reg         flash  = 1'b0;
19reg [ 3:0]  ticker = 1'b1;
20
21// Временные регистры
22reg [7:0]   rmask;      // Маска из знакогенератора
23reg [7:0]   rcolor;     // Рисуемый цвет
24reg [7:0]   tdata;      // Временный байт
25
26wire xborder = x == 10'd799;
27wire yborder = y ==  9'd448;
28wire visible = x >= 48 && x < 48+640 && y >= 35 && y <= 35+400;
29
30// Горизонтальная и вертикальная синхронизация
31assign hs = x  < 48+640+16;
32assign vs = y >= 35+400+12;
33
34// Выравнивание
35wire [9:0]  xv = x - 40; // Не 48, а 40, из-за конвейерного метода
36wire [8:0]  yv = y - 35; // А здесь 35
37
38// Итоговый пиксель
39wire        pix = rmask[ ~xv[2:0] ];
40
41// Если =0, то цвет букв становится цветом фона
42wire        enfore  = ~(flash & rcolor[7]);
43
44// Номер знакоместа от 0 до 1999
45wire [10:0] cplace   = yv[8:4]*80 + xv[9:3];
46wire        acursor  = (cursor + 1 == cplace) & (yv[3:0] >= 4'hE);
47
48// Вычисление цвета
49wire [ 3:0] curcolor = (pix & enfore) | (acursor & flash) ? rcolor[3:0] : rcolor[6:4];
50wire [ 5:0] outcolor =
51    //                    RR GG BB
52    curcolor == 4'h0 ? 6'b00_00_00 : // Черный
53    curcolor == 4'h1 ? 6'b00_00_01 : // Синий
54    curcolor == 4'h2 ? 6'b00_01_00 : // Зеленый
55    curcolor == 4'h3 ? 6'b00_01_01 : // Бирюзовый
56    curcolor == 4'h4 ? 6'b01_00_00 : // Красный
57    curcolor == 4'h5 ? 6'b01_00_01 : // Пурпурный
58    curcolor == 4'h6 ? 6'b01_01_00 : // Коричневый
59    curcolor == 4'h7 ? 6'b10_10_10 : // Светло-серый
60    curcolor == 4'h8 ? 6'b01_01_01 : // Темно-серый
61    curcolor == 4'h9 ? 6'b00_00_11 : // Ярко-синий
62    curcolor == 4'hA ? 6'b00_11_00 : // Ярко-зеленый
63    curcolor == 4'hB ? 6'b00_11_11 : // Голубой
64    curcolor == 4'hC ? 6'b11_00_00 : // Ярко-красный
65    curcolor == 4'hD ? 6'b11_00_11 : // Розовый
66    curcolor == 4'hE ? 6'b11_11_00 : // Желтый
67                       6'b11_11_11;  // Белый
68
69assign {r, g, b} = visible ? outcolor : 6'b00_00_00;
70
71always @(posedge clock) begin
72
73    x <= xborder ? 1'b0 : x + 1'b1;
74    y <= xborder && yborder ? 1'b0 : (xborder ? y + 1'b1 : y);
75
76    /* verilator lint_off CASEINCOMPLETE */
77    case (xv[2:0])
78
79        // Запрос символа
80        3'h0: begin address     <= {cplace, 1'b0}; end
81        // Сохранить символ в tdata, запрос цвета (соседний байт)
82        3'h1: begin address[0]  <= 1'b1; tdata <= data; end
83        // Запрос знакогенератора, сохранение цвета
84        3'h2: begin address     <= {1'b1, tdata, yv[3:0]}; tdata <= data; end
85        // Новые значения для конвейера
86        3'h7: begin rmask       <= data; rcolor <= tdata; end
87
88    endcase
89
90    if (xborder && yborder) begin
91
92        ticker <= ticker + 1'b1;
93        flash  <= ticker ? flash : ~flash;
94
95    end
96
97end
98
99endmodule

§ Код на Жабноскрипте

1class module_vga {
2
3    constructor() {
4
5        this.r = {
6            x: 0,       // 9
7            y: 0,       // 8
8            flash: 0,   // 1
9            ticker: 0,  // 4
10            rmask: 0,   // 8
11            rcolor: 0,  // 8
12            tdata: 0,   // 8
13        };
14
15        this.io = {
16            r: 0,
17            g: 0,
18            b: 0,
19            hs: 0,
20            vs: 0,
21            address: 0,
22            data: 0,
23            cursor: 0,
24        }
25
26        this.w = {};
27    }
28
29    precompute() {
30
31        this.w.xborder = +this.r.x === 799 ? 1 : 0;
32        this.w.yborder = +this.r.y === 448 ? 1 : 0;
33        this.w.visible = this.r.x >= 48 && this.r.x < 48 + 640 && this.r.y >= 35 && this.r.y <= 35 + 400 ? 1 : 0;
34
35        this.io.hs = this.r.x < 48 + 640 + 16 ? 1 : 0;
36        this.io.vs = this.r.y >= 35 + 400 + 12 ? 1 : 0;
37
38        this.w.xv = this.r.x - 40;
39        this.w.yv = this.r.y - 35;
40
41        this.w.pix      = (this.r.rmask >> ((~this.w.xv) & 7)) & 1;
42        this.w.enfore   = (this.r.flash & (this.r.rcolor >> 7) & 1) ? 0 : 1;
43        this.w.cplace   = 80*((this.w.yv >> 4) & 31) + (this.w.xv >> 3);
44        this.w.acursor  = (this.io.cursor + 1 === this.w.cplace) && ((this.w.yv & 15) >= 14) ? 1 : 0;
45        this.w.curcolor = (this.w.pix & this.w.enfore) || (this.w.acursor & this.r.flash) ? (this.r.rcolor & 15) : (this.r.rcolor >> 4) & 7;
46
47        switch (this.w.curcolor) {
48
49            case 0: this.w.outcolor  = 0 * 16 + 0 * 4 + 0; break;
50            case 1: this.w.outcolor  = 0 * 16 + 0 * 4 + 1; break;
51            case 2: this.w.outcolor  = 0 * 16 + 1 * 4 + 0; break;
52            case 3: this.w.outcolor  = 0 * 16 + 1 * 4 + 1; break;
53            case 4: this.w.outcolor  = 1 * 16 + 0 * 4 + 0; break;
54            case 5: this.w.outcolor  = 1 * 16 + 0 * 4 + 1; break;
55            case 6: this.w.outcolor  = 1 * 16 + 1 * 4 + 0; break;
56            case 7: this.w.outcolor  = 2 * 16 + 2 * 4 + 2; break;
57            case 8: this.w.outcolor  = 1 * 16 + 1 * 4 + 1; break;
58            case 9: this.w.outcolor  = 0 * 16 + 0 * 4 + 3; break;
59            case 10: this.w.outcolor = 0 * 16 + 3 * 4 + 0; break;
60            case 11: this.w.outcolor = 0 * 16 + 3 * 4 + 3; break;
61            case 12: this.w.outcolor = 3 * 16 + 0 * 4 + 0; break;
62            case 13: this.w.outcolor = 3 * 16 + 0 * 4 + 3; break;
63            case 14: this.w.outcolor = 3 * 16 + 3 * 4 + 0; break;
64            case 15: this.w.outcolor = 3 * 16 + 3 * 4 + 3; break;
65        }
66
67        this.io.r = this.w.visible ? (this.w.outcolor >> 4) & 3 : 0;
68        this.io.g = this.w.visible ? (this.w.outcolor >> 2) & 3 : 0;
69        this.io.b = this.w.visible ? (this.w.outcolor >> 0) & 3 : 0;
70    }
71
72    clock() {
73
74        this.precompute();
75
76        let _x  = this.w.xborder ? 0 : this.r.x + 1;
77        let _y  = this.w.xborder && this.w.yborder ? 0 : (this.w.xborder ? this.r.y + 1 : this.r.y);
78        let _tdata  = this.r.tdata,
79            _rmask  = this.r.rmask,
80            _rcolor = this.r.rcolor;
81
82        switch (this.w.xv & 7) {
83
84            // Запрос символа
85            case 0:
86
87                this.io.address = this.w.cplace << 1;
88                break;
89
90            // Сохранить символ в tdata, запрос цвета (соседний байт)
91            case 1:
92
93                this.io.address |= 1;
94                _tdata = this.io.data;
95                break;
96
97            // Запрос знакогенератора, сохранение цвета
98            case 2:
99
100                this.io.address = (this.w.yv & 15) + 16*(this.r.tdata & 255) + 4096;
101                _tdata = this.io.data;
102                break;
103
104            case 7:
105
106                _rmask  = this.io.data;
107                _rcolor = this.r.tdata;
108                break;
109        }
110
111        if (this.w.xborder && this.w.yborder) {
112
113            this.r.flash  = this.r.ticker > 0 ? this.r.flash : 1 - this.r.flash;
114            this.r.ticker = (this.r.ticker + 1) & 15;
115        }
116
117        this.r.x = _x;
118        this.r.y = _y;
119        this.r.tdata = _tdata;
120        this.r.rmask  = _rmask;
121        this.r.rcolor = _rcolor;
122    }
123}
124
125class vgajs extends Dos2D {
126
127    init() {
128
129        this.cls(0);
130
131        this.mod  = new module_vga();
132        this.vmem = new Uint8Array(4096);
133
134        this.mod.io.cursor = 2;
135
136        for (let i = 0; i < 4000; i += 2) {
137
138            this.vmem[i]   = (i >> 1) & 255;
139            this.vmem[i+1] = (i >> 1) & 255;
140        }
141
142        this.x = 0; this._hs = 1;
143        this.y = 0; this._vs = 0;
144    }
145
146    // 640 x 400 x 70
147    vga(hs, vs, color) {
148
149        if (hs) this.x++;
150
151        if (this._hs === 0 && hs === 1) {
152            this.x = 0;
153            this.y++;
154        }
155
156        if (this._vs === 1 && vs === 0) {
157            this.x = 0;
158            this.y = 0;
159        }
160
161        this._hs = hs;
162        this._vs = vs;
163
164        this.pset(this.x - 48, this.y - 35, color);
165    }
166
167    loop() {
168
169        // this.measure(0);
170        for (let i = 0; i < 75000; i++) {
171
172            // Чтение из видеопамяти
173            let address = this.mod.io.address;
174            if (address >= 4096) {
175                this.mod.io.data = this._font16[ address & 0xFFF ];
176            } else {
177                this.mod.io.data = this.vmem[address];
178            }
179
180            this.mod.clock();
181
182            let hs    = this.mod.io.hs;
183            let vs    = this.mod.io.vs;
184            let color = (65536 * this.mod.io.r * 85) + 256 * this.mod.io.g * 85 + this.mod.io.b * 85;
185
186            this.vga(hs, vs, color);
187        }
188        // this.measure(1);
189    }
190}