Skip to content

Commit

Permalink
am4: introduce synchronous model
Browse files Browse the repository at this point in the history
The reverse engineering of M4 processor is completed, the synchronous
model running on real FPGA is introduced.

The synchronous M4 model:

  - runs on top of real FPGAs
  - supports Wishbone compatible front-end bus
  - ported and tested on multiple development boards

Also bug with ena_ms frequency was fixed, the 1MHz ena_us was
divided by 1024 instead of 1000 resulting in 976Hz ena_ms strobe
frequency (was missed "else" keyword). The system timer frequency
was not affected.

Signed-off-by: 1801BM1 <[email protected]>
  • Loading branch information
1801BM1 committed Dec 22, 2020
1 parent faf64eb commit 5715b96
Show file tree
Hide file tree
Showing 36 changed files with 2,102 additions and 67 deletions.
181 changes: 181 additions & 0 deletions am4/hdl/wbc/rtl/am4_alu.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
//
// Copyright (c) 2020 by [email protected]
//______________________________________________________________________________
//
// Four-bit Microprocessor Slice
//
module am4_alu
(
input clk, // clock positive
input ena, // clock enable
input [8:0] i, // operation code
input [3:0] a, // port A address (readonly)
input [3:0] b, // port B address (read/write)
input [15:0] d, // direct data input
output [15:0] y, // data output
output [15:0] r, // ram[a] output
//
input cin, // carry input
output c8, // carry output, LSB
output c16, // carry output, MSB
output v8, // arithmetic overflow, LSB
output v16, // arithmetic overflow, MSB
output zl, // zero flag, LSB
output zh, // zero flag, MSB
output f7, // msb of LSB
output f15, // msb of MSB
//
input ram0_i, // shift register stack lsb LSB
output ram0_o, //
input ram7_i, // shift register stack msb LSB
output ram7_o, //
input ram8_i, // shift register stack lsb MSB
output ram8_o, //
input ram15_i, // shift register stack msb MSB
output ram15_o, //
input q0_i, // shift Q-register lsb LSB
output q0_o, //
input q15_i, // shift Q-register msb MSB
output q15_o //
);

//______________________________________________________________________________
//
reg [15:0] q_ram[15:0]; // RAM array
wire [15:0] i_ram; // RAM input mux
//
reg [15:0] q_reg; // Q register
wire [15:0] q_mux; // Q register input mux
//
wire [15:0] r_alu; // ALU input mux R
wire [15:0] r_ext; //
wire [15:0] s_alu; // ALU input mux S
wire [15:0] s_ext; //
wire [15:0] f_alu; // ALU result output
//
wire c6, c7, c14, c15; // carries
wire [16:0] sum; // sum to get carries

//______________________________________________________________________________
//
// Initialization to eliminate uncertain simulation
//
integer m;

initial
begin
for (m=0; m<16; m = m + 1)
q_ram[m] = 4'b0000;
q_reg = 4'b0000;
end

//______________________________________________________________________________
//
// RAM registers and RAM input mux
//
assign i_ram = (i[8:7] == 2'b00) ? 16'h0000 : // QREG, NOP
(i[8:7] == 2'b01) ? f_alu : // RAMA, RAMF - load
(i[8:7] == 2'b10) ? {ram15_i, f_alu[15:9], //
ram7_i, f_alu[7:1]} : // RAMQD, RAMD - shift down/right
(i[8:7] == 2'b11) ? {f_alu[14:8], ram8_i, //
f_alu[6:0], ram0_i} : // RAMQU, RAMU - shift up/left
16'h0000; // default

always @(posedge clk) if ((i[8:7] != 2'b00) & ena) q_ram[b] <= i_ram;

assign ram0_o = f_alu[0];
assign ram7_o = f_alu[7];
assign ram8_o = f_alu[8];
assign ram15_o = f_alu[15];

//______________________________________________________________________________
//
// Q-register input mux and latches
//
assign q_mux = (i[8:6] == 3'b000) ? f_alu : // QREG
(i[8:6] == 3'b100) ? {q15_i, q_reg[15:1]} : // RAMQD - shift down/right
(i[8:6] == 3'b110) ? {q_reg[14:0], q0_i} : q_reg; // RAMQU - shift up/left

assign q0_o = q_reg[0];
assign q15_o = q_reg[15];

always @(posedge clk) if (ena) q_reg <= q_mux;

//______________________________________________________________________________
//
// Y-output mux and RAMA output
//
assign y = (i[8:6] == 3'b010) ? q_ram[a] : f_alu;
assign r = q_ram[a];

//______________________________________________________________________________
//
// ALU input muxes
//
assign r_alu = (i[2:0] == 3'b000) ? q_ram[a] : // AQ
(i[2:0] == 3'b001) ? q_ram[a] : // AB
(i[2:0] == 3'b010) ? 16'h0000 : // ZQ
(i[2:0] == 3'b011) ? 16'h0000 : // ZB
(i[2:0] == 3'b100) ? 16'h0000 : d; // ZA, DA, DQ, DZ

assign s_alu = (i[2:0] == 3'b000) ? q_reg : // AQ
(i[2:0] == 3'b001) ? q_ram[b] : // AB
(i[2:0] == 3'b010) ? q_reg : // ZQ
(i[2:0] == 3'b011) ? q_ram[b] : // ZB
(i[2:0] == 3'b100) ? q_ram[a] : // ZA
(i[2:0] == 3'b101) ? q_ram[a] : // DA
(i[2:0] == 3'b110) ? q_reg : 16'h0000; // DQ, DZ

assign r_ext = ( (i[5:3] == 3'b001)
| (i[5:3] == 3'b101)
| (i[5:3] == 3'b110)) ? ~r_alu : r_alu;

assign s_ext = (i[5:3] == 3'b010) ? ~s_alu : s_alu;
assign sum = {1'b0, r_ext} + {1'b0, s_ext} + {16'h0000, cin};

//
// Carry from alu_f[n]->alu_f[n+1]
//
assign c6 = s_ext[7] ^ r_ext[7] ^ sum[7]; // f_alu[6]->f_alu[7]
assign c7 = s_ext[8] ^ r_ext[8] ^ sum[8]; // f_alu[7]->f_alu[8]
assign c14 = s_ext[15] ^ r_ext[15] ^ sum[15]; // f_alu[14]->f_alu[15]
assign c15 = sum[16];
//
// ALU result
//
assign f_alu = (i[5:3] == 3'b000) ? sum[15:0] : // ADD
(i[5:3] == 3'b001) ? sum[15:0] : // SUBR
(i[5:3] == 3'b010) ? sum[15:0] : // SUBS
(i[5:3] == 3'b011) ? r_ext | s_ext : // OR
(i[5:3] == 3'b100) ? r_ext & s_ext : // AND
(i[5:3] == 3'b101) ? r_ext & s_ext : // NOTRS
(i[5:3] == 3'b110) ? ~r_ext ^ s_ext : // EXOR
(i[5:3] == 3'b111) ? ~r_ext ^ s_ext : 16'h0000; // EXNOR

//
// The carry and overflow flags over logical instructions
// are not used by microcode, we can simplify
//
assign c8 = (i[5:3] == 3'b000) ? c7 : // ADD
(i[5:3] == 3'b001) ? c7 : // SUBR
(i[5:3] == 3'b010) ? c7 : cin; // SUBS

assign c16 = (i[5:3] == 3'b000) ? c15 : // ADD
(i[5:3] == 3'b001) ? c15 : // SUBR
(i[5:3] == 3'b010) ? c15 : cin; // SUBS

assign v8 = (i[5:3] == 3'b000) ? c6 ^ c7 : // ADD
(i[5:3] == 3'b001) ? c6 ^ c7 : // SUBR
(i[5:3] == 3'b010) ? c6 ^ c7 : 1'b0; // SUBS

assign v16 = (i[5:3] == 3'b000) ? c14 ^ c15 : // ADD
(i[5:3] == 3'b001) ? c14 ^ c15 : // SUBR
(i[5:3] == 3'b010) ? c14 ^ c15 : 1'b0; // SUBS

assign f7 = f_alu[7];
assign f15 = f_alu[15];
assign zl = ~|f_alu[7:0];
assign zh = ~|f_alu[15:8];
//______________________________________________________________________________
//
endmodule
53 changes: 53 additions & 0 deletions am4/hdl/wbc/rtl/am4_mcrom.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright (c) 2020 by [email protected]
//
//______________________________________________________________________________
//
// M4 microcode ROM, for debug and simulating only
//
module mcrom
(
input clk, // input clock
input ena, // clock enable
input [9:0] addr, // instruction address
output [55:0] data // output read opcode
);

//______________________________________________________________________________
//
// Memory array and its inititialization with K1656RE1-001/007 content
//
reg [55:0] rom [0:1023];
reg [55:0] q;
integer i;

initial
begin
end


initial
begin
for (i=0; i<1023; i = i + 1)
begin
rom[i] = 56'h00000000000000;
end
//
// The filename for MicROM content might be explicitly
// specified in synthesys/simulating tool settings
//
`ifdef M4_FILE_MICROM
$readmemh(`M4_FILE_MICROM, rom);
`else
$readmemh("..\\..\\..\\..\\rom\\mc.rom", rom);
`endif
end

//______________________________________________________________________________
//
assign data = q;
always @ (posedge clk) if (ena) q <= rom[addr];

endmodule


148 changes: 148 additions & 0 deletions am4/hdl/wbc/rtl/am4_plm.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//
// Copyright (c) 2020 by [email protected]
//______________________________________________________________________________
//
// M4 processor PDP-11 instruction decoding PLM (D123, D136)
//
module plm_dec
(
input [15:0] ins, // PDP-11 instruction opcode
output reg bf, // byte operation flag
output reg [6:0] ad // address of microcode
);

wire rs = ins[11:9] == 3'b000;
wire rd = ins[5:3] == 3'b000;

always @(*)
casex(ins) // clrb/comb/incb/decb
16'o105xxx: bf = 1'b1; // negb/adcb/sbcb/tstb
16'o1060xx: bf = 1'b1; // rorb
16'o1061xx: bf = 1'b1; // rolb
16'o1062xx: bf = 1'b1; // asrb
16'o1063xx: bf = 1'b1; // aslb
16'o1064xx: bf = 1'b1; // mtps
16'o1067xx: bf = 1'b1; // mfps
16'o11xxxx: bf = 1'b1; // movb
16'o12xxxx: bf = 1'b1; // cmpb
16'o13xxxx: bf = 1'b1; // bitb
16'o14xxxx: bf = 1'b1; // bicb
16'o15xxxx: bf = 1'b1; // bisb
default: bf = 1'b0;
endcase

always @(*)
casex(ins)
16'o000000: ad = 7'h00; // halt
16'o000001: ad = 7'h03; // wait
16'o000002: ad = 7'h02; // rti
16'o000003: ad = 7'h04; // bpt
16'o000004: ad = 7'h07; // iot
16'o000005: ad = 7'h06; // reset
16'o000006: ad = 7'h02; // rtt
16'o0001xx: ad = 7'h0E; // jmp
16'o00020x: ad = 7'h36; // rts
16'o00024x: ad = 7'h40; // clx
16'o00025x: ad = 7'h40; // clx
16'o00026x: ad = 7'h43; // sex
16'o00027x: ad = 7'h43; // sex
16'o0003xx: ad = ~rd ? 7'h41 // swab
/* 16'o00030x: */ : 7'h44; // swab Rd
16'o0004xx: ad = 7'h1F; // br
16'o0005xx: ad = 7'h1F; //
16'o0006xx: ad = 7'h1F; //
16'o0007xx: ad = 7'h1F; //
16'o001xxx: ad = 7'h1F; // bne/beq
16'o002xxx: ad = 7'h1F; // bge/blt
16'o003xxx: ad = 7'h1F; // bgt/ble
16'o004xxx: ad = 7'h37; // jsr
//
16'o0050xx: ad = ~rd ? 7'h12 // clr
/* 16'o00500x: */ : 7'h22; // clr Rd
16'o0051xx: ad = ~rd ? 7'h14 // com
/* 16'o00510x: */ : 7'h24; // com Rd
16'o0052xx: ad = ~rd ? 7'h16 // inc
/* 16'o00520x: */ : 7'h26; // inc Rd
16'o0053xx: ad = ~rd ? 7'h18 // dec
/* 16'o00530x: */ : 7'h28; // dec Rd
16'o0054xx: ad = ~rd ? 7'h1A // neg
/* 16'o00540x: */ : 7'h2A; // neg Rd
16'o0055xx: ad = ~rd ? 7'h0D // adc
/* 16'o00550x: */ : 7'h4D; // adc Rd
16'o0056xx: ad = ~rd ? 7'h53 // sbc
/* 16'o00560x: */ : 7'h4A; // sbc Rd
16'o0057xx: ad = ~rd ? 7'h2C // tst
/* 16'o00570x: */ : 7'h6C; // tst Rd
16'o0060xx: ad = ~rd ? 7'h15 // ror
/* 16'o00600x: */ : 7'h55; // ror Rd
16'o0061xx: ad = ~rd ? 7'h17 // rol
/* 16'o00610x: */ : 7'h56; // rol Rd
16'o0062xx: ad = ~rd ? 7'h1B // asr
/* 16'o00620x: */ : 7'h5B; // asr Rd
16'o0063xx: ad = ~rd ? 7'h1D // asl
/* 16'o00630x: */ : 7'h5C; // asl Rd
16'o0064xx: ad = 7'h09; // mark
16'o0067xx: ad = 7'h08; // sxt
//
16'o01xxxx: ad = (~rs | ~rd) ? 7'h31 // mov
/* 16'o010x0x: */ : 7'h30; // mov Rs, Rd
16'o02xxxx: ad = (~rs | ~rd) ? 7'h13 // cmp
/* 16'o020x0x: */ : 7'h3A; // cmp Rs, Rd
16'o03xxxx: ad = (~rs | ~rd) ? 7'h1C // bit
/* 16'o030x0x: */ : 7'h3C; // bit Rs, Rd
16'o04xxxx: ad = (~rs | ~rd) ? 7'h1E // bic
/* 16'o040x0x: */ : 7'h3E; // bic Rs, Rd
16'o05xxxx: ad = (~rs | ~rd) ? 7'h10 // bis
/* 16'o050x0x: */ : 7'h20; // bis Rs, Rd
16'o06xxxx: ad = ~rs ? 7'h35 // add
/* 16'o060xxx: */ : ~rd ? 7'h34 // add Rs, xx
/* 16'o060x0x: */ : 7'h74; // add Rs, Rd
16'o070xxx: ad = 7'h47; // mul
16'o071xxx: ad = 7'h48; // div
16'o072xxx: ad = 7'h42; // ash
16'o073xxx: ad = 7'h45; // ashc
16'o074xxx: ad = 7'h0B; // xor
16'o07500x: ad = 7'h0F; // fadd
16'o07501x: ad = 7'h0F; // fsub
16'o07502x: ad = 7'h0F; // fmul
16'o07503x: ad = 7'h0F; // fdiv
16'o077xxx: ad = 7'h0A; // sob
//
16'o100xxx: ad = 7'h1F; // bpl/bmi
16'o101xxx: ad = 7'h1F; // bhi/blos
16'o102xxx: ad = 7'h1F; // bvc/bvs
16'o103xxx: ad = 7'h1F; // bcc/bcs
16'o1040xx: ad = 7'h39; // emt
16'o1041xx: ad = 7'h39; // emt
16'o1042xx: ad = 7'h39; // emt
16'o1043xx: ad = 7'h39; // emt
16'o1044xx: ad = 7'h38; // trap
16'o1045xx: ad = 7'h38; // trap
16'o1046xx: ad = 7'h38; // trap
16'o1047xx: ad = 7'h38; // trap
16'o1050xx: ad = 7'h25; // clrb
16'o1051xx: ad = 7'h27; // comb
16'o1052xx: ad = 7'h29; // incb
16'o1053xx: ad = 7'h2B; // decb
16'o1054xx: ad = 7'h2D; // negb
16'o1055xx: ad = 7'h51; // adcb
16'o1056xx: ad = 7'h52; // sbcb
16'o1057xx: ad = 7'h2F; // tstb
16'o1060xx: ad = 7'h54; // rorb
16'o1061xx: ad = 7'h59; // rolb
16'o1062xx: ad = 7'h5A; // asrb
16'o1063xx: ad = 7'h5F; // aslb
16'o1064xx: ad = 7'h2E; // mtps
16'o1067xx: ad = 7'h0C; // mfps
16'o11xxxx: ad = (~rs | ~rd) ? 7'h33 // movb
/* 16'o110x0x: */ : 7'h32; // movb Rd, Rs
16'o12xxxx: ad = 7'h3D; // cmpb
16'o13xxxx: ad = 7'h3F; // bitb
16'o14xxxx: ad = 7'h21; // bicb
16'o15xxxx: ad = 7'h23; // bisb
16'o16xxxx: ad = (~rs | ~rd) ? 7'h19 // sub
/* 16'o160x0x: */ : 7'h3B; // sub Rd, Rs
default: ad = 7'h01; // undefined
endcase

endmodule
Loading

0 comments on commit 5715b96

Please sign in to comment.