[科创文物翻新计划]基于Verilog,指令集扩展的KC-LS1u处理器SoC实现(长期填坑)
洪啸宇
rpg-72021/02/01原创 IC菜鸟成长手记 IP:江苏

前言与愿景

KC-LS1u这一74处理器实现是本论坛七年之前的重磅级作品,一定程度上来说算是国内74逻辑门自制CPU的巅峰之作,但非常可惜的一点是,原作者并未计划实现该处理器的FPGA实现。作为切换到了基于HDL的设计并从中极大受益的爱好者,在此本人建议各位数字电路爱好者自学基础的硬件描述语言,这可以帮助各位脱离繁琐的基于逻辑门和触发器的设计风格,并极大的加速各位的设计和验证过程。

本工程主要面向74CPU爱好者,旨在作为一个简单完整,基于Verilog HDL并包含了绝大多数工程中常用HDL语法的CPU及SoC实现的教学性工程,起到抛砖引玉帮助更多的爱好者用上用好现代化的FPGA/数字集成电路设计验证流程的作用。本文也将着重于在接下来陆续更新该设计的解析,并将基于各模块相关代码穿插对应Verilog HDL的语法点讲解。

鉴于本工程的的SoC框架将具备良好的可扩展性和高度的灵活性,如果可能,该框架将作为一个相对完善,开箱即用的SoC框架,供各位74爱好者快速迁移设计到一个相对现代的微处理器框架中,体验数字前端的高效设计流程。

本处理器特性

本处理器实现实现了完整的74-LS1u基本指令集

本处理器实现扩展了C/D两个GPR

本处理器实现了简单的中断、现场保存、返回机制

本处理器具备固定64K页面的MMU及32位物理地址扩展

本处理器具备可配置的直接映射式L1指令缓存/全相连L1指令-数据一体缓存/无缓存模式

本处理器具备一个基于Wishbone简化的同步SRAM总线接口,可以稍加修改挂接XXXXXXXXXXXXX上的诸多软核实现

从龙少原处理器设计说起

龙少原处理器指令可以大致拆分为如下的部分:

[15:11]
[10:8]
[7:0]
处理器功能选择(数据源选择)
目标寄存器选择/跳转源选择
立即数/ALU功能选择

对于发布了硬件的KC-LS1U处理器而言,其译码真值表如下:

功能选择译码值
功能
备注
0x01
跳转大类
无需写总线
0x02
ALU功能大类
244×1 (U9)
0x04
加载内存
244×1 (?)
0x06
加载立即数
244×1 (U16)
0x07
A << 1;
244×1(U5)
0x08
{A[6:0],B[7]}
U5
0x09
A>>1
244×1(U6)
0x0a
{A[7],A[7:1]}
U6
0x0b
B<<1
244×1(U7)
0x0c
B>>1
244×1(U8)
0x0d
{B[7],B[7:1]}
U8
0x0e
{A[0],B[7:1]}
U8

本处理器(KC-LS1u+)扩展功能:

功能选择译码值功能备注
0x05读入C寄存器GPR,无自动保存
0x07读入D寄存器GPR,无自动保存
0x03
读取XREG
现场保存寄存器/核心配置寄存器
0x08
将A/B寄存器写入XREG

目标寄存器选择译码:

码值
目标寄存器
跳转模式
0x0
N/A (C)
N/A(中断返回
0x1
A
A[7]==0
0x2
B
B[7]==0
0x3
A0
A!=B
0x4
A1
ALU不进位
0x5
A2
无条件跳转
0x6
N/A (D)
N/A
0x7
内存写
N/A

ALU选择为ALU功能选择/运算-逻辑模式切换/进位输入端,直通指令接口中[7:2]位。

 龙少处理器中存在的怪东西

  1. 谜之244

    大多数244的存在可以解释得通(作为数据源选择器的组成部分),但是U20/U21这两个直通的244,不知道是拿来干嘛的

    2.“阻塞”寄存器堆

    将138的输出直接怼进273时钟输入端,导致不能连续写入同一个寄存器

    3.兼做跳转寄存器的内存地址寄存器

    LS1U没法高效存取内存有一大半的锅得这个设计背,跳转是你,存取还是你,还只写不读,我是A0/A1/A2,我TM很心累

本处理器的层次

SNAP.png

处理器核KC_LS1u_plus

名称
位宽
作用
clk
1
时钟输入
rst
1
高有效复位
IVEC_addr
[23:0]
中断向量地址
INT
1
中断触发
IN_ISP
1
中断服务指示输出
iaddr
[23:0]
指令地址
iaddr_next
[23:0]
下一条指令地址
instr
[15:0]
指令输入
daddr
[23:0]
数据地址
dread
1
读数据指示
dwrite
1
写数据指示
WAIT
1
处理器等待输入
ddata_i
[7:0]
处理器数据输入
ddata_o
[7:0]
处理器数据输出

-------------WIP----------------------

本处理器设计中使用的部分Verilog语法案例

建议的多路器写法

//KC_LS1u_plus.v
reg [7:0]XREGr;//扩展寄存器组读取端口
always@(*)
begin
    case(xreg_addr)//使用case的可读性相对assign好得多
        3'h0:XREGr=RET0;
        3'h1:XREGr=RET1;
        3'h2:XREGr=RET1;
        3'h3:XREGr=RTA0;
        3'h4:XREGr=RTA1;
        3'h5:XREGr=RTA2;
    default :XREGr=8'hxx;//default状态下为X而非定值,更节约逻辑
    endcase            //(综合器放弃default情况,传入非法值可能输出任意输入而非专门产生给定值情况)
end

异步握手 WIP

WIP

WIP

defparam或#(.所改参数(传入参数)) 配合  #(parameter x=123456)灵活变更工程参数&使用generate for完成批量例化

//l1.v
/*****该模块为Cache内存的顶层模块,展示了使用defparam改变模块内部参数的语法******/
defparam l1_ram.datawidth=DATA_WIDTH;
defparam l1_ram.cache_depth=CACHE_DEPTH;
cachemem                l1_ram
(
    .raddr          (read_addr),
    .waddr          (write_addr),
    .di             (write_data),
    .we             (we),
    .bsel           (byte_sel),
    .dato           (cache_read),
    .clk            (clk)
);
//cachemem.v
module cachemem
#
(
    parameter datawidth=64,
    cache_depth=2048
)
(
    input cwait,
    input [addr_wid-1:0]raddr,
    input [addr_wid-1:0]waddr,
    input [datawidth-1:0]di,
    input we,
    input [cswidth-1:0]bsel,
    output [datawidth-1:0]dato,
    input rclk,
    input wclk
);

localparam cswidth=datawidth/8;  //localparam是不可从外部改变的局部参数
localparam addr_wid =$clog2(cache_depth);
localparam addr_lsb=$clog2(cswidth);
genvar i;
generate //generate批量例化的时候只能用#(.所改参数(传入参数))的语法
    for(i=0;i<cswidth;i=i+1) 
    begin : cacheblk
        cachemem8 #(.memdepth(cache_depth)) cacheunit //注意该行,更建议使用该语法
        (
            .cwait(cwait),
            .rclk(rclk),
            .wclk(wclk),
            .raddr(raddr),//[addr_wid+addr_lsb-1:addr_lsb]
            .waddr(waddr),//[addr_wid+addr_lsb-1:addr_lsb]
            .di(di[7+8*i:0+8*i]),
            .dato(dato[7+8*i:0+8*i]),
            .we(we&bsel[i])
        );
    end
endgenerate
endmodule

module cachemem8 //一块8b位宽同步SRAM
#(
    parameter memdepth = 1024,
    memaddr=$clog2(memdepth)
)
(
    input cwait,
    input rclk,
    input wclk,
    input [memaddr-1:0]raddr,
    input [memaddr-1:0]waddr,
    input [7:0]di,
    output reg[7:0]dato,
    input we
 );
reg [7:0]memcell[memdepth-1:0];
//begin //: GENERIC_SSRAM
always @(posedge rclk)
begin
    if(cwait)dato<=dato;
    else dato<=memcell[raddr];
    
end
always @(posedge wclk)
    if(we)memcell[waddr]<=di;
endmodule

术语表

术语/信号缩写
全称
译名
ISP

Interrupt Service Program

中断服务程序
Entry/Line
Cache Entry/ Cache Line
高速缓存表项
Tag
Cache Tag
高速缓存标签










截至2021-02-17的项目进展

KC-LS1u/KC-LS1u+的处理器RTL实现完成,并部分指令完成验证

L1 Cache模块设计完成,并通过简单的测试

完成了MMU,在处理器中扩展简单的中断/异常/线程处理机制

最小化的SoC框架设计完成(FSB8片外总线/中断和时钟控制器/Systick中断计时器/Syscall系统调用控制器/2KB Scratchpad RAM)

最小化的SoC非常轻量,可以塞入GW1N-1芯片中

完成了部分外设(SPI/UART/GPIO/Timer)

完成了SoC部分外设的简单验证

未来计划

完成对处理器的完整验证,有条件则使用UVM验证框架

解耦CPU/总线时钟,尝试实现核心倍频/睿频机制

基于现有的CPU访存状态机扩展DMA功能

基于安路AL3S10NG88芯片实现对原版设计部分兼容的完整SoC设计,并绘制开发板

对称多处理机(俺寻思没有D-Cache约等于几乎没有多核一致性问题,那么SMP应该相对好做)


基于本项目仍在进行并且将长期更新的考量,核心和工程选择暂时仅在Github发布,在设计/验证结束前暂不上传至科创论坛。

项目地址:XXXXXXXXXXXXXXXXXX/RPG-7/SoC-KC-LS1u


[修改于 3年9个月前 - 2021/04/09 03:26:10]

来自:计算机科学 / 计算机电子学电子信息 / 电子技术
8
 
10
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
通货膨胀气
3年11个月前 IP:江西
890040

有考虑过基于RISC-V指令集的吗?期待!

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
rpg-7作者
3年11个月前 IP:江苏
890063
引用通货膨胀气发表于1楼的内容
有考虑过基于RISC-V指令集的吗?期待!

我们有基于RISC-V设计并长期维护的SoC,

四级流水线RISC-V64IMA XXXXXXXXXXXXXXXXXX/RV-AT/PVS464

(在建)基于SIMD扩展的RISC-V GPU XXXXXXXXXXXXXXXXXX/RPG-7/HGA101_GPU/


引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
分立元件
3年11个月前 IP:海南
890066

使用FPGA验证CPU效率提升恐怖 sticker

引用
评论(1)
2
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
rpg-7作者
3年11个月前 修改于 3年11个月前 IP:江苏
890086

Debug手记:处理器中断响应Bug

Bug仿真波形如下:

isp_fault.png

图中观察可以发现,当中断信号到来时,处理器中中断响应组件并未按照期待完成当前指令后将ISP地址填充至PC

可能的bug来源:

1.下一条指令选择器中对等待状态的处理,我们可以考虑让中断来时强行跳转至ISP,但这样不符合我们对处理器行为的期待

cause1.png

2.中断握手流程未考虑到等待状态

查询代码可发现处理器中断处理流程如下:

cause2-1.png


cause2.png

当复位时清除ISP标志int_service

当中断来临(INT=1且ISP标志=0),保存现场(PC+1/A0A1A2),ISP标志置位

将PC置为ISP地址(在PC_NEXT处实现)

如果返回,清除中断标志位并从RET/RTA寄存器中弹出PC+1/A0A1A2(未在此展示)

看到这里,这里修改代码,通过在进入ISP前检查WAIT状态,仿真故障不再复现

how.png

debug_finished.png

可见,在WAIT状态结束后,正常跳转进入ISP

有奖竞猜:这段中断处理流程的描述中,还有一个Bug,欢迎在评论区中竞猜指出,答对有奖

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
虎哥
3年11个月前 IP:四川
890103
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
神之觉醒
3年11个月前 修改于 3年11个月前 IP:广西
890105

麻烦楼主了,,, 以前的烂摊子有劳楼主了收拾了,表示支持,前阵子SMT32片子用得舒服就把自产计划搁置了,刚用得舒服现在居然涨价 sticker


引用
评论(1)
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
rpg-7作者
3年11个月前 IP:江苏
890298

昨日进展:验证了cache的自动填充,Cache/总线状态机基本正确

cachefill_start.png

可见处理器被置等待外设状态,状态机从总线RAM中读入数据装填入Cache RAM

cachefill_complete.png

Cache Entry装填完成,放开外设忙状态,CPU开始跑

cache_refill.png

当跳转后发生缺页(line_miss=1),重新装填Cache RAM,同时替换Cache Tag(refill_tag)

 综上,该Cache工作基本正确,在单次读写上似乎还有Bug


引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
rpg-7作者
3年10个月前 修改于 3年10个月前 IP:江苏
890845

今日进展:

Burst_XTNL.jpg

验证了从片外同步前端总线以同步/异步模式连续读取指令流的正确性

BURST_ASYNC.jpg

验证了片内控制/外设,片内功能基本正常

MIN_verify_halfway.png

完成了片内MMU的设计,核心现已支持32bit扩展寻址

这个设计现在基本榨干了GW1N-1这个芯片的全部LUT资源

UTIL.jpg

为了完成新增功能,修复debug过程中出现的1919个bug,从核心到外设,现已新增114514个粪设计


引用
评论
2
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}